CRM-15603 - Standardize punctuation of event checkboxes
[civicrm-core.git] / CRM / Event / Form / ManageEvent / Registration.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 *
31 * @package CRM
32 * @copyright CiviCRM LLC (c) 2004-2014
33 * $Id$
34 *
35 */
36
37 /**
38 * This class generates form components for processing Event
39 *
40 */
41 class CRM_Event_Form_ManageEvent_Registration extends CRM_Event_Form_ManageEvent {
42
43 /**
44 * what blocks should we show and hide.
45 *
46 * @var CRM_Core_ShowHideBlocks
47 */
48 protected $_showHide;
49
50 protected $_profilePostMultiple = array();
51 protected $_profilePostMultipleAdd = array();
52
53 /**
54 * Function to set variables up before form is built
55 *
56 * @return void
57 * @access public
58 */
59 function preProcess() {
60 $this->_addProfileBottom = CRM_Utils_Array::value('addProfileBottom', $_GET, FALSE);
61 $this->_profileBottomNum = CRM_Utils_Array::value('addProfileNum', $_GET, 0);
62 $this->_addProfileBottomAdd = CRM_Utils_Array::value('addProfileBottomAdd', $_GET, FALSE);
63 $this->_profileBottomNumAdd = CRM_Utils_Array::value('addProfileNumAdd', $_GET, 0);
64
65 parent::preProcess();
66
67 $this->assign('addProfileBottom', $this->_addProfileBottom);
68 $this->assign('profileBottomNum', $this->_profileBottomNum);
69
70 $urlParams = "id={$this->_id}&addProfileBottom=1&qfKey={$this->controller->_key}";
71 $this->assign('addProfileParams', $urlParams);
72
73 if ($addProfileBottom = CRM_Utils_Array::value('custom_post_id_multiple', $_POST)) {
74 foreach (array_keys($addProfileBottom) as $profileNum) {
75 self::buildMultipleProfileBottom($this, $profileNum);
76 }
77 }
78
79 $this->assign('addProfileBottomAdd', $this->_addProfileBottomAdd);
80 $this->assign('profileBottomNumAdd', $this->_profileBottomNumAdd);
81
82 $urlParamsAdd = "id={$this->_id}&addProfileBottomAdd=1&qfKey={$this->controller->_key}";
83 $this->assign('addProfileParamsAdd', $urlParamsAdd);
84
85 if ($addProfileBottomAdd = CRM_Utils_Array::value('additional_custom_post_id_multiple', $_POST)) {
86 foreach (array_keys($addProfileBottomAdd) as $profileNum) {
87 self::buildMultipleProfileBottom($this, $profileNum, 'additional_', ts('Profile for Additional Participants'));
88 }
89 }
90 }
91
92 /**
93 * This function sets the default values for the form.
94 * the default values are retrieved from the database
95 *
96 * @access public
97 *
98 * @return void
99 */
100 function setDefaultValues() {
101 if ($this->_addProfileBottom || $this->_addProfileBottomAdd) {
102 return;
103 }
104 $eventId = $this->_id;
105
106 $defaults = parent::setDefaultValues();
107
108 $this->setShowHide($defaults);
109 if (isset($eventId)) {
110 $params = array('id' => $eventId);
111 CRM_Event_BAO_Event::retrieve($params, $defaults);
112
113 $ufJoinParams = array(
114 'entity_table' => 'civicrm_event',
115 'module' => 'CiviEvent',
116 'entity_id' => $eventId,
117 );
118
119 list($defaults['custom_pre_id'],
120 $defaults['custom_post']
121 ) = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams);
122
123 // Get the id for the event registration profile
124 $eventRegistrationIdParams = $eventRegistrationIdDefaults = array(
125 'name' => 'event_registration',
126 );
127 CRM_Core_BAO_UFGroup::retrieve($eventRegistrationIdParams, $eventRegistrationIdDefaults);
128
129 // Set event registration as the default profile if none selected
130 if (!$defaults['custom_pre_id'] && count($defaults['custom_post']) == 0) {
131 $defaults['custom_pre_id'] = CRM_Utils_Array::value('id', $eventRegistrationIdDefaults);
132 }
133 if (isset($defaults['custom_post']) && is_numeric($defaults['custom_post'])) {
134 $defaults['custom_post_id'] = $defaults['custom_post'];
135 }
136 elseif (!empty($defaults['custom_post'])) {
137 $defaults['custom_post_id'] = $defaults['custom_post'][0];
138 unset($defaults['custom_post'][0]);
139 $this->_profilePostMultiple = $defaults['custom_post'];
140 foreach ($defaults['custom_post'] as $key => $value) {
141 self::buildMultipleProfileBottom($this, $key);
142 $defaults["custom_post_id_multiple[$key]"] = $value;
143 }
144 }
145
146 $this->assign('profilePostMultiple', CRM_Utils_Array::value('custom_post', $defaults));
147
148 if (!empty($defaults['is_multiple_registrations'])) {
149 // CRM-4377: set additional participants’ profiles – set to ‘none’ if explicitly unset (non-active)
150
151 $ufJoinAddParams = array(
152 'entity_table' => 'civicrm_event',
153 'module' => 'CiviEvent_Additional',
154 'entity_id' => $eventId,
155 );
156
157 list($defaults['additional_custom_pre_id'],
158 $defaults['additional_custom_post']
159 ) = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinAddParams);
160
161 if (isset($defaults['additional_custom_post']) && is_numeric($defaults['additional_custom_post'])) {
162 $defaults['additional_custom_post_id'] = $defaults['additional_custom_post'];
163 }
164 elseif (!empty($defaults['additional_custom_post'])) {
165 $defaults['additional_custom_post_id'] = $defaults['additional_custom_post'][0];
166 unset($defaults['additional_custom_post'][0]);
167
168 $this->_profilePostMultipleAdd = $defaults['additional_custom_post'];
169 foreach ($defaults['additional_custom_post'] as $key => $value) {
170 self::buildMultipleProfileBottom($this, $key, 'additional_', ts('Profile for Additional Participants'));
171 $defaults["additional_custom_post_id_multiple[$key]"] = $value;
172 }
173 }
174 $this->assign('profilePostMultipleAdd', CRM_Utils_Array::value('additional_custom_post', $defaults));
175 }
176 }
177 else {
178 $defaults['is_email_confirm'] = 0;
179 }
180
181 // provide defaults for required fields if empty (and as a 'hint' for approval message field)
182 $defaults['registration_link_text'] = CRM_Utils_Array::value('registration_link_text', $defaults, ts('Register Now'));
183 $defaults['confirm_title'] = CRM_Utils_Array::value('confirm_title', $defaults, ts('Confirm Your Registration Information'));
184 $defaults['thankyou_title'] = CRM_Utils_Array::value('thankyou_title', $defaults, ts('Thank You for Registering'));
185 $defaults['approval_req_text'] = CRM_Utils_Array::value('approval_req_text', $defaults, ts('Participation in this event requires approval. Submit your registration request here. Once approved, you will receive an email with a link to a web page where you can complete the registration process.'));
186
187 if (!empty($defaults['registration_start_date'])) {
188 list($defaults['registration_start_date'],
189 $defaults['registration_start_date_time']
190 ) = CRM_Utils_Date::setDateDefaults($defaults['registration_start_date'],
191 'activityDateTime'
192 );
193 }
194
195 if (!empty($defaults['registration_end_date'])) {
196 list($defaults['registration_end_date'],
197 $defaults['registration_end_date_time']
198 ) = CRM_Utils_Date::setDateDefaults($defaults['registration_end_date'],
199 'activityDateTime'
200 );
201 }
202
203 return $defaults;
204 }
205
206 /**
207 * Fix what blocks to show/hide based on the default values set
208 *
209 * @param array $defaults the array of default values
210 *
211 * @internal param bool $force should we set show hide based on input defaults
212 *
213 * @return void
214 */
215 function setShowHide($defaults) {
216 $this->_showHide = new CRM_Core_ShowHideBlocks(array('registration' => 1),
217 ''
218 );
219 if (empty($defaults)) {
220 $this->_showHide->addHide('registration');
221 $this->_showHide->addHide('id-approval-text');
222 }
223 else {
224 if (empty($defaults['requires_approval'])) {
225 $this->_showHide->addHide('id-approval-text');
226 }
227 }
228 $this->assign('defaultsEmpty', empty($defaults));
229 $this->_showHide->addToTemplate();
230 }
231
232 /**
233 * Function to build the form
234 *
235 * @return void
236 * @access public
237 */
238 public function buildQuickForm() {
239 if ($this->_addProfileBottom) {
240 return self::buildMultipleProfileBottom($this, $this->_profileBottomNum);
241 }
242
243 if ($this->_addProfileBottomAdd) {
244 return self::buildMultipleProfileBottom($this, $this->_profileBottomNumAdd, 'additional_', ts('Profile for Additional Participants'));
245 }
246
247 $this->applyFilter('__ALL__', 'trim');
248 $attributes = CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event');
249
250 $this->addElement('checkbox',
251 'is_online_registration',
252 ts('Allow Online Registration'),
253 NULL,
254 array(
255 'onclick' => "return showHideByValue('is_online_registration',
256 '',
257 'registration_blocks',
258 'block',
259 'radio',
260 false );",
261 )
262 );
263
264 $this->add('text', 'registration_link_text', ts('Registration Link Text'));
265
266 if (!$this->_isTemplate) {
267 $this->addDateTime('registration_start_date', ts('Registration Start Date'), FALSE, array('formatType' => 'activityDateTime'));
268 $this->addDateTime('registration_end_date', ts('Registration End Date'), FALSE, array('formatType' => 'activityDateTime'));
269 }
270
271 $params = array(
272 'used' => 'Supervised',
273 'contact_type' => 'Individual',
274 );
275 $dedupeRuleFields = CRM_Dedupe_BAO_Rule::dedupeRuleFields($params);
276
277 foreach ($dedupeRuleFields as $key => $fields) {
278 $ruleFields[$key] = ucwords(str_replace('_', ' ', $fields));
279 }
280
281 $this->addElement('checkbox',
282 'is_multiple_registrations',
283 ts('Register multiple participants?')
284 );
285
286 $this->addElement('checkbox',
287 'allow_same_participant_emails',
288 ts('Same email address?')
289 );
290 $this->assign('ruleFields', json_encode($ruleFields));
291
292 $dedupeRules = array(
293 '' => '- Unsupervised rule -',
294 );
295 $dedupeRules += CRM_Dedupe_BAO_RuleGroup::getByType('Individual');
296 $this->add('select', 'dedupe_rule_group_id', ts('Duplicate matching rule'), $dedupeRules);
297
298 $participantStatuses = CRM_Event_PseudoConstant::participantStatus();
299 if (in_array('Awaiting approval', $participantStatuses) and in_array('Pending from approval', $participantStatuses) and in_array('Rejected', $participantStatuses)) {
300 $this->addElement('checkbox',
301 'requires_approval',
302 ts('Require participant approval?'),
303 NULL,
304 array('onclick' => "return showHideByValue('requires_approval', '', 'id-approval-text', 'table-row', 'radio', false);")
305 );
306 $this->add('textarea', 'approval_req_text', ts('Approval message'), $attributes['approval_req_text']);
307 }
308
309 $this->add('text', 'expiration_time', ts('Pending participant expiration (hours)'));
310 $this->addRule('expiration_time', ts('Please enter the number of hours (as an integer).'), 'integer');
311
312 self::buildRegistrationBlock($this);
313 self::buildConfirmationBlock($this);
314 self::buildMailBlock($this);
315 self::buildThankYouBlock($this);
316
317 parent::buildQuickForm();
318 }
319
320 /**
321 * Function to build Registration Block
322 *
323 * @param $form
324 *
325 * @internal param int $pageId
326 * @static
327 */
328 function buildRegistrationBlock(&$form) {
329 $attributes = CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event');
330 $attributes['intro_text']['click_wysiwyg'] = true;
331 $form->addWysiwyg('intro_text', ts('Introductory Text'), $attributes['intro_text']);
332 // FIXME: This hack forces height of editor to 175px. Need to modify QF classes for editors to allow passing
333 // explicit height and width.
334 $footerAttribs = array(
335 'rows' => 2,
336 'cols' => 40,
337 'click_wysiwyg' => true,
338 );
339 $form->addWysiwyg('footer_text', ts('Footer Text'), $footerAttribs);
340
341 extract( self::getProfileSelectorTypes() );
342 //CRM-15427
343 $form->addProfileSelector( 'custom_pre_id', ts('Include Profile') . '<br />' . ts('(top of page)'), $allowCoreTypes, $allowSubTypes, $profileEntities, TRUE);
344 $form->addProfileSelector( 'custom_post_id', ts('Include Profile') . '<br />' . ts('(bottom of page)'), $allowCoreTypes, $allowSubTypes, $profileEntities, TRUE);
345
346 $form->addProfileSelector( 'additional_custom_pre_id', ts('Profile for Additional Participants') . '<br />' . ts('(top of page)'), $allowCoreTypes, $allowSubTypes, $profileEntities, TRUE);
347 $form->addProfileSelector( 'additional_custom_post_id', ts('Profile for Additional Participants') . '<br />' . ts('(bottom of page)'), $allowCoreTypes, $allowSubTypes, $profileEntities, TRUE);
348 }
349
350 /**
351 * Subroutine to insert a Profile Editor widget
352 * depends on getProfileSelectorTypes
353 *
354 * @param array &$form
355 * @param int $count unique index
356 * @param string $prefix dom element ID prefix
357 * @param string $label Label
358 * @param array $configs Optional, for addProfileSelector(), defaults to using getProfileSelectorTypes()
359 **/
360 function buildMultipleProfileBottom(&$form, $count, $prefix = '', $label = 'Include Profile', $configs = null) {
361 extract( ( is_null($configs) ) ? self::getProfileSelectorTypes() : $configs );
362 $element = $prefix . "custom_post_id_multiple[$count]";
363 $label .= '<br />'.ts('(bottom of page)');
364 $form->addProfileSelector( $element, $label, $allowCoreTypes, $allowSubTypes, $profileEntities, TRUE);
365 }
366
367 /**
368 * Create initializers for addprofileSelector
369 *
370 * @return array( 'allowCoreTypes' => array(), 'allowSubTypes' => array(), 'profileEntities' => array() )
371 **/
372 static function getProfileSelectorTypes() {
373 $configs = array(
374 'allowCoreTypes' => array(),
375 'allowSubTypes' => array(),
376 'profileEntities' => array(),
377 );
378
379 $configs['allowCoreTypes'][] = 'Contact';
380 $configs['allowCoreTypes'][] = 'Individual';
381 $configs['allowCoreTypes'][] = 'Participant';
382 //CRM-15427
383 $id = CRM_Utils_Request::retrieve( 'id' , 'Integer' );
384 if ($id) {
385 $participantEventType = CRM_Core_DAO::getFieldValue("CRM_Event_DAO_Event", $id, 'event_type_id', 'id');
386 $participantRole = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $id, 'default_role_id');
387 $configs['allowSubTypes']['ParticipantEventName'] = array($id);
388 $configs['allowSubTypes']['ParticipantEventType'] = array($participantEventType);
389 $configs['allowSubTypes']['ParticipantRole'] = array($participantRole);
390 }
391 $configs['profileEntities'][] = array('entity_name' => 'contact_1', 'entity_type' => 'IndividualModel');
392 $configs['profileEntities'][] = array('entity_name' => 'participant_1', 'entity_type' => 'ParticipantModel', 'entity_sub_type' => '*');
393
394 return $configs;
395 }
396
397 /**
398 * Function to build Confirmation Block
399 *
400 * @param $form
401 *
402 * @internal param int $pageId
403 * @static
404 */
405 function buildConfirmationBlock(&$form) {
406 $attributes = CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event');
407 $attributes['confirm_text']['click_wysiwyg'] = true;
408 // CRM-11182 - Optional confirmation page for free events
409 $is_monetary = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Event', $form->_id, 'is_monetary');
410 $form->assign('is_monetary', $is_monetary);
411 if ($is_monetary == "0") {
412 $form->addYesNo('is_confirm_enabled', ts('Use a confirmation screen?'), NULL, NULL, array('onclick' => "return showHideByValue('is_confirm_enabled','','confirm_screen_settings','block','radio',false);"));
413 }
414 $form->add('text', 'confirm_title', ts('Title'), $attributes['confirm_title']);
415 $form->addWysiwyg('confirm_text', ts('Introductory Text'), $attributes['confirm_text']);
416 // FIXME: This hack forces height of editor to 175px. Need to modify QF classes for editors to allow passing
417 // explicit height and width.
418 $footerAttribs = array(
419 'rows' => 2,
420 'cols' => 40,
421 'click_wysiwyg' => true,
422 );
423 $form->addWysiwyg('confirm_footer_text', ts('Footer Text'), $footerAttribs);
424 }
425
426 /**
427 * Function to build Email Block
428 *
429 * @param $form
430 *
431 * @internal param int $pageId
432 * @static
433 */
434 function buildMailBlock(&$form) {
435 $form->registerRule('emailList', 'callback', 'emailList', 'CRM_Utils_Rule');
436 $attributes = CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event');
437 $form->addYesNo('is_email_confirm', ts('Send Confirmation Email?'), NULL, NULL, array('onclick' => "return showHideByValue('is_email_confirm','','confirmEmail','block','radio',false);"));
438 $form->add('textarea', 'confirm_email_text', ts('Text'), $attributes['confirm_email_text']);
439 $form->add('text', 'cc_confirm', ts('CC Confirmation To'), CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event', 'cc_confirm'));
440 $form->addRule('cc_confirm', ts('Please enter a valid list of comma delimited email addresses'), 'emailList');
441 $form->add('text', 'bcc_confirm', ts('BCC Confirmation To'), CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event', 'bcc_confirm'));
442 $form->addRule('bcc_confirm', ts('Please enter a valid list of comma delimited email addresses'), 'emailList');
443 $form->add('text', 'confirm_from_name', ts('Confirm From Name'));
444 $form->add('text', 'confirm_from_email', ts('Confirm From Email'));
445 $form->addRule('confirm_from_email', ts('Email is not valid.'), 'email');
446 }
447
448 /**
449 * @param $form
450 */
451 function buildThankYouBlock(&$form) {
452 $attributes = CRM_Core_DAO::getAttribute('CRM_Event_DAO_Event');
453 $attributes['thankyou_text']['click_wysiwyg'] = true;
454 $form->add('text', 'thankyou_title', ts('Title'), $attributes['thankyou_title']);
455 $form->addWysiwyg('thankyou_text', ts('Introductory Text'), $attributes['thankyou_text']);
456 // FIXME: This hack forces height of editor to 175px. Need to modify QF classes for editors to allow passing
457 // explicit height and width.
458 $footerAttribs = array(
459 'rows' => 2,
460 'cols' => 40,
461 'click_wysiwyg' => true,
462 );
463 $form->addWysiwyg('thankyou_footer_text', ts('Footer Text'), $footerAttribs);
464 }
465
466 /**
467 * Add local and global form rules
468 *
469 * @access protected
470 *
471 * @return void
472 */
473 function addRules() {
474 if ($this->_addProfileBottom || $this->_addProfileBottomAdd) {
475 return;
476 }
477 $this->addFormRule(array('CRM_Event_Form_ManageEvent_Registration', 'formRule'), $this);
478 }
479
480 /**
481 * global validation rules for the form
482 *
483 * @param $values
484 * @param $files
485 * @param $form
486 *
487 * @internal param array $fields posted values of the form
488 *
489 * @return array list of errors to be posted back to the form
490 * @static
491 * @access public
492 */
493 static function formRule($values, $files, $form) {
494 if (!empty($values['is_online_registration'])) {
495
496 if (!$values['confirm_title']) {
497 $errorMsg['confirm_title'] = ts('Please enter a Title for the registration Confirmation Page');
498 }
499 if (!$values['thankyou_title']) {
500 $errorMsg['thankyou_title'] = ts('Please enter a Title for the registration Thank-you Page');
501 }
502 if ($values['is_email_confirm']) {
503 if (!$values['confirm_from_name']) {
504 $errorMsg['confirm_from_name'] = ts('Please enter Confirmation Email FROM Name.');
505 }
506
507 if (!$values['confirm_from_email']) {
508 $errorMsg['confirm_from_email'] = ts('Please enter Confirmation Email FROM Email Address.');
509 }
510 }
511
512 if (
513 isset($values['registration_start_date']) &&
514 isset($values['registration_end_date'])
515 ) {
516 $start = CRM_Utils_Date::processDate($values['registration_start_date']);
517 $end = CRM_Utils_Date::processDate($values['registration_end_date']);
518 if ($end < $start) {
519 $errorMsg['registration_end_date'] = ts('Registration end date should be after Registration start date');
520 }
521 }
522
523 //check that the selected profiles have either firstname+lastname or email required
524 $profileIds = array(
525 CRM_Utils_Array::value('custom_pre_id', $values),
526 CRM_Utils_Array::value('custom_post_id', $values),
527 );
528 $additionalProfileIds = array(
529 CRM_Utils_Array::value('additional_custom_pre_id', $values),
530 CRM_Utils_Array::value('additional_custom_post_id', $values),
531 );
532 //additional profile fields default to main if not set
533 if (!is_numeric($additionalProfileIds[0])) {
534 $additionalProfileIds[0] = $profileIds[0];
535 }
536 if (!is_numeric($additionalProfileIds[1])) {
537 $additionalProfileIds[1] = $profileIds[1];
538 }
539 //add multiple profiles if set
540 self::addMultipleProfiles($profileIds, $values, 'custom_post_id_multiple');
541 self::addMultipleProfiles($additionalProfileIds, $values, 'additional_custom_post_id_multiple');
542 $isProfileComplete = self::isProfileComplete($profileIds);
543 $isAdditionalProfileComplete = self::isProfileComplete($additionalProfileIds);
544
545 //Check main profiles have an email address available if 'send confirmation email' is selected
546 if ($values['is_email_confirm']) {
547 $emailFields = self::getEmailFields($profileIds);
548 if (!count($emailFields)) {
549 $errorMsg['is_email_confirm'] = ts("Please add a profile with an email address if 'Send Confirmation Email?' is selected");
550 }
551 }
552 $additionalCustomPreId = $additionalCustomPostId = NULL;
553 $isPreError = $isPostError = TRUE;
554 if (!empty($values['allow_same_participant_emails']) && !empty($values['is_multiple_registrations'])) {
555 $types = array_merge(array('Individual'), CRM_Contact_BAO_ContactType::subTypes('Individual'));
556 $profiles = CRM_Core_BAO_UFGroup::getProfiles($types);
557
558 //check for additional custom pre profile
559 $additionalCustomPreId = CRM_Utils_Array::value('additional_custom_pre_id', $values);
560 if (!empty($additionalCustomPreId)) {
561 if (!($additionalCustomPreId == 'none')) {
562 $customPreId = $additionalCustomPreId;
563 }
564 else {
565 $isPreError = FALSE;
566 }
567 }
568 else {
569 $customPreId = !empty($values['custom_pre_id']) ? $values['custom_pre_id'] : NULL;
570 }
571 //check whether the additional custom pre profile is of type 'Individual' and its subtypes
572 if (!empty($customPreId)) {
573 $profileTypes = CRM_Core_BAO_UFGroup::profileGroups($customPreId);
574 foreach ($types as $individualTypes) {
575 if (in_array($individualTypes, $profileTypes)) {
576 $isPreError = FALSE;
577 break;
578 }
579 }
580 }
581 else {
582 $isPreError = FALSE;
583 }
584
585 // We don't have required Individual fields in the pre-custom profile, so now check the post-custom profile
586 if ($isPreError) {
587 $additionalCustomPostId = CRM_Utils_Array::value('additional_custom_post_id', $values);
588 if (!empty($additionalCustomPostId)) {
589 if (!($additionalCustomPostId == 'none')) {
590 $customPostId = $additionalCustomPostId;
591 }
592 else {
593 $isPostError = FALSE;
594 }
595 }
596 else {
597 $customPostId = !empty($values['custom_post_id']) ? $values['custom_post_id'] : NULL;
598 }
599 //check whether the additional custom post profile is of type 'Individual' and its subtypes
600 if (!empty($customPostId)) {
601 $profileTypes = CRM_Core_BAO_UFGroup::profileGroups($customPostId);
602 foreach ($types as $individualTypes) {
603 if (in_array($individualTypes, $profileTypes)) {
604 $isPostError = FALSE;
605 break;
606 }
607 }
608 }
609 else {
610 $isPostError = FALSE;
611 }
612
613 if (empty($customPreId) && empty($customPostId)) {
614 $errorMsg['additional_custom_pre_id'] = ts("Allow multiple registrations from the same email address requires a profile of type 'Individual'");
615 }
616 if ($isPostError) {
617 $errorMsg['additional_custom_post_id'] = ts("Allow multiple registrations from the same email address requires a profile of type 'Individual'");
618 }
619 }
620 }
621 if (!$isProfileComplete) {
622 $errorMsg['custom_pre_id'] = ts("Please include a Profile for online registration that contains an Email Address field and / or First Name + Last Name fields.");
623 }
624 if (!$isAdditionalProfileComplete) {
625 $errorMsg['additional_custom_pre_id'] = ts("Please include a Profile for online registration of additional participants that contains an Email Address field and / or First Name + Last Name fields.");
626 }
627
628 // // CRM-8485
629 // $config = CRM_Core_Config::singleton();
630 // if ( $config->doNotAttachPDFReceipt ) {
631 // if (!empty($values['custom_post_id_multiple'])) {
632 // foreach( $values['custom_post_id_multiple'] as $count => $customPostMultiple ) {
633 // if ( $customPostMultiple ) {
634 // $errorMsg["custom_post_id_multiple[{$count}]"] = ts('Please disable PDF receipt as an attachment in <a href="%1">Miscellaneous Settings</a> if you want to add additional profiles.', array( 1 => CRM_Utils_System::url( 'civicrm/admin/setting/misc', 'reset=1' ) ) );
635 // break;
636 // }
637 // }
638 // }
639 //
640 // if (!empty($values['is_multiple_registrations']) &&
641 // CRM_Utils_Array::value('additional_custom_post_id_multiple', $values) ) {
642 // foreach( $values['additional_custom_post_id_multiple'] as $count => $customPostMultiple ) {
643 // if ( $customPostMultiple ) {
644 // $errorMsg["additional_custom_post_id_multiple[{$count}]"] = ts('Please disable PDF receipt as an attachment in <a href="%1">Miscellaneous Settings</a> if you want to add additional profiles.', array( 1 => CRM_Utils_System::url( 'civicrm/admin/setting/misc', 'reset=1' ) ) );
645 // break;
646 // }
647 // }
648 // }
649 // }
650
651 if (!empty($errorMsg)) {
652 if (!empty($values['custom_post_id_multiple'])) {
653 foreach ($values['custom_post_id_multiple'] as $count => $customPostMultiple) {
654 self::buildMultipleProfileBottom($form, $count);
655 }
656 $form->assign('profilePostMultiple', $values['custom_post_id_multiple']);
657 }
658 if (!empty($values['additional_custom_post_id_multiple'])) {
659 foreach ($values['additional_custom_post_id_multiple'] as $count => $customPostMultiple) {
660 self::buildMultipleProfileBottom($form, $count, 'additional_', ts('Profile for Additional Participants'));
661 }
662 $form->assign('profilePostMultipleAdd', $values['additional_custom_post_id_multiple']);
663 }
664 }
665 }
666
667 if (!empty($errorMsg)) {
668 return $errorMsg;
669 }
670
671 return TRUE;
672 }
673
674 /**
675 * Collect all email fields for an array of profile ids
676 *
677 * @param $profileIds
678 * @return boolean
679 */
680 static function getEmailFields($profileIds) {
681 $emailFields = array();
682 foreach ($profileIds as $profileId) {
683 if ($profileId && is_numeric($profileId)) {
684 $fields = CRM_Core_BAO_UFGroup::getFields($profileId);
685 foreach ($fields as $field) {
686 if (substr_count($field['name'], 'email')) {
687 $emailFields[] = $field;
688 }
689 }
690 }
691 }
692 return $emailFields;
693 }
694
695 /**
696 * Check if a profile contains required fields
697 *
698 * @param $profileIds
699 * @return boolean
700 */
701 static function isProfileComplete($profileIds) {
702 $profileReqFields = array();
703 foreach ($profileIds as $profileId) {
704 if ($profileId && is_numeric($profileId)) {
705 $fields = CRM_Core_BAO_UFGroup::getFields($profileId);
706 foreach ($fields as $field) {
707 switch (TRUE) {
708 case substr_count($field['name'], 'email'):
709 $profileReqFields[] = 'email';
710 break;
711
712 case substr_count($field['name'], 'first_name'):
713 $profileReqFields[] = 'first_name';
714 break;
715
716 case substr_count($field['name'], 'last_name'):
717 $profileReqFields[] = 'last_name';
718 break;
719 }
720 }
721 }
722 }
723 $profileComplete = (in_array('email', $profileReqFields)
724 || (in_array('first_name', $profileReqFields) && in_array('last_name', $profileReqFields))
725 );
726 return $profileComplete;
727 }
728
729 /**
730 * Check if the profiles collect enough information to dedupe
731 *
732 * @param $profileIds
733 * @param int $rgId
734 * @return boolean
735 */
736
737 function canProfilesDedupe($profileIds, $rgId = 0) {
738
739 // find the unsupervised rule
740
741 $rgParams = array(
742 'used' => 'Unsupervised',
743 'contact_type' => 'Individual',
744 );
745 if ($rgId > 0) {
746 $rgParams['id'] = $rgId;
747 }
748 $activeRg = CRM_Dedupe_BAO_RuleGroup::dedupeRuleFieldsWeight($rgParams);
749
750 // get the combinations that could be a match for the rule
751 $okCombos = $combos = array();
752 CRM_Dedupe_BAO_RuleGroup::combos($activeRg[0], $activeRg[1], $combos);
753
754 // create an index of what combinations involve each field
755 $index = array();
756 foreach ($combos as $comboid => $combo) {
757 foreach ($combo as $cfield) {
758 $index[$cfield][$comboid] = true;
759 }
760 $combos[$comboid] = array_fill_keys($combo, 0);
761 $okCombos[$comboid] = array_fill_keys($combo, 2);
762 }
763
764 // get profiles and see if they have the necessary combos
765 $profileReqFields = array();
766 foreach ($profileIds as $profileId) {
767 if ($profileId && is_numeric($profileId)) {
768 $fields = CRM_Core_BAO_UFGroup::getFields($profileId);
769
770 // walk through the fields in the profile
771 foreach ($fields as $field) {
772
773 // check each of the fields in the index against the profile field
774 foreach ($index as $ifield => $icombos) {
775 if(strpos($field['name'], $ifield) !== false) {
776
777 // we found the field in the profile, now record it in the index
778 foreach ($icombos as $icombo => $dontcare) {
779 $combos[$icombo][$ifield] = ($combos[$icombo][$ifield] != 2 && !$field['is_required']) ? 1 : 2;
780
781 if ($combos[$icombo] == $okCombos[$icombo]) {
782 // if any combo is complete with 2s (all fields are present and required), we can go home
783 return 2;
784 }
785 }
786 }
787 }
788 }
789 }
790 }
791
792 // check the combos to see if everything is > 0
793 foreach ($combos as $comboid => $combo) {
794 $complete = false;
795 foreach ($combo as $cfield) {
796 if ($cfield > 0) {
797 $complete = true;
798 }
799 else {
800 // this combo isn't complete--skip to the next combo
801 continue 2;
802 }
803 }
804 if ($complete) { return 1; }
805 }
806
807 // no combo succeeded
808 return 0;
809 }
810
811 /**
812 * Add additional profiles from the form to an array of profile ids.
813 *
814 */
815 static function addMultipleProfiles(&$profileIds, $values, $field) {
816 if ($multipleProfiles = CRM_Utils_Array::value($field, $values)) {
817 foreach ($multipleProfiles as $profileId) {
818 $profileIds[] = $profileId;
819 }
820 }
821 }
822
823 /**
824 * Function to process the form
825 *
826 * @access public
827 *
828 * @return void
829 */
830 public function postProcess() {
831 $params = $this->exportValues();
832
833 $params['id'] = $this->_id;
834
835 // format params
836 $params['is_online_registration'] = CRM_Utils_Array::value('is_online_registration', $params, FALSE);
837 $params['is_confirm_enabled'] = CRM_Utils_Array::value('is_confirm_enabled', $params, FALSE); // CRM-11182
838 $params['is_multiple_registrations'] = CRM_Utils_Array::value('is_multiple_registrations', $params, FALSE);
839 $params['allow_same_participant_emails'] = CRM_Utils_Array::value('allow_same_participant_emails', $params, FALSE);
840 $params['requires_approval'] = CRM_Utils_Array::value('requires_approval', $params, FALSE);
841
842 // reset is_email confirm if not online reg
843 if (!$params['is_online_registration']) {
844 $params['is_email_confirm'] = FALSE;
845 }
846
847 if (!$this->_isTemplate) {
848 $params['registration_start_date'] = CRM_Utils_Date::processDate($params['registration_start_date'],
849 $params['registration_start_date_time'],
850 TRUE
851 );
852 $params['registration_end_date'] = CRM_Utils_Date::processDate($params['registration_end_date'],
853 $params['registration_end_date_time'],
854 TRUE
855 );
856 }
857
858 CRM_Event_BAO_Event::add($params);
859
860 // also update the ProfileModule tables
861 $ufJoinParams = array(
862 'is_active' => 1,
863 'module' => 'CiviEvent',
864 'entity_table' => 'civicrm_event',
865 'entity_id' => $this->_id,
866 );
867
868
869 // first delete all past entries
870 CRM_Core_BAO_UFJoin::deleteAll($ufJoinParams);
871
872 $uf = array();
873 $wt = 2;
874 if (!empty($params['custom_pre_id'])) {
875 $uf[1] = $params['custom_pre_id'];
876 $wt = 1;
877 }
878
879 if (!empty($params['custom_post_id'])) {
880 $uf[2] = $params['custom_post_id'];
881 }
882
883 if (!empty($params['custom_post_id_multiple'])) {
884 $uf = array_merge($uf, $params['custom_post_id_multiple']);
885 }
886 $uf = array_values($uf);
887 if (!empty($uf)) {
888 foreach ($uf as $weight => $ufGroupId) {
889 $ufJoinParams['weight'] = $weight + $wt;
890 $ufJoinParams['uf_group_id'] = $ufGroupId;
891 CRM_Core_BAO_UFJoin::create($ufJoinParams);
892 unset($ufJoinParams['id']);
893 }
894 }
895 // also update the ProfileModule tables
896 $ufJoinParamsAdd = array(
897 'is_active' => 1,
898 'module' => 'CiviEvent_Additional',
899 'entity_table' => 'civicrm_event',
900 'entity_id' => $this->_id,
901 );
902
903 // first delete all past entries
904 CRM_Core_BAO_UFJoin::deleteAll($ufJoinParamsAdd);
905 if (!empty($params['is_multiple_registrations'])) {
906 $ufAdd = array();
907 $wtAdd = 2;
908
909 if (array_key_exists('additional_custom_pre_id', $params)) {
910 if (empty($params['additional_custom_pre_id'])) {
911 $ufAdd[1] = $params['custom_pre_id'];
912 $wtAdd = 1;
913 }
914 elseif (CRM_Utils_Array::value('additional_custom_pre_id', $params) == 'none') {}
915 else {
916 $ufAdd[1] = $params['additional_custom_pre_id'];
917 $wtAdd = 1;
918 }
919 }
920
921 if (array_key_exists('additional_custom_post_id', $params)) {
922 if (empty($params['additional_custom_post_id'])) {
923 $ufAdd[2] = $params['custom_post_id'];
924 }
925 elseif (CRM_Utils_Array::value('additional_custom_post_id', $params) == 'none') {}
926 else {
927 $ufAdd[2] = $params['additional_custom_post_id'];
928 }
929 }
930
931 if (!empty($params['additional_custom_post_id_multiple'])) {
932 $additionalPostMultiple = array();
933 foreach ($params['additional_custom_post_id_multiple'] as $key => $value) {
934 if (is_null($value) && !empty($params['custom_post_id'])) {
935 $additionalPostMultiple[$key] = $params['custom_post_id'];
936 }
937 elseif ($value == 'none') {
938 continue;
939 }
940 elseif ($value) {
941 $additionalPostMultiple[$key] = $value;
942 }
943 }
944 $ufAdd = array_merge($ufAdd, $additionalPostMultiple);
945 }
946
947 $ufAdd = array_values($ufAdd);
948 if (!empty($ufAdd)) {
949 foreach ($ufAdd as $weightAdd => $ufGroupIdAdd) {
950
951 $ufJoinParamsAdd['weight'] = $weightAdd + $wtAdd;
952 $ufJoinParamsAdd['uf_group_id'] = $ufGroupIdAdd;
953
954 CRM_Core_BAO_UFJoin::create($ufJoinParamsAdd);
955 unset($ufJoinParamsAdd['id']);
956 }
957 }
958 }
959
960 // get the profiles to evaluate what they collect
961 $profileIds = array(
962 CRM_Utils_Array::value('custom_pre_id', $params),
963 CRM_Utils_Array::value('custom_post_id', $params),
964 );
965 $additionalProfileIds = array(
966 CRM_Utils_Array::value('additional_custom_pre_id', $params),
967 CRM_Utils_Array::value('additional_custom_post_id', $params),
968 );
969 // additional profile fields default to main if not set
970 if (!is_numeric($additionalProfileIds[0])) {
971 $additionalProfileIds[0] = $profileIds[0];
972 }
973 if (!is_numeric($additionalProfileIds[1])) {
974 $additionalProfileIds[1] = $profileIds[1];
975 }
976 //add multiple profiles if set
977 self::addMultipleProfiles($profileIds, $params, 'custom_post_id_multiple');
978 self::addMultipleProfiles($additionalProfileIds, $params, 'additional_custom_post_id_multiple');
979
980 $cantDedupe = false;
981 $rgId = CRM_Utils_Array::value('dedupe_rule_group_id', $params, 0);
982
983 switch (self::canProfilesDedupe($profileIds, $rgId)) {
984 case 0:
985 $dedupeTitle = 'Duplicate Matching Impossible';
986 $cantDedupe = ts("The selected profiles do not contain the fields necessary to match registrations with existing contacts. This means all anonymous registrations will result in a new contact.");
987 break;
988 case 1:
989 $dedupeTitle = 'Duplicate Contacts Possible';
990 $cantDedupe = ts("The selected profiles can collect enough information to match registrations with existing contacts, but not all of the relevant fields are required. Anonymous registrations may result in duplicate contacts.");
991 }
992 if (!empty($params['is_multiple_registrations'])) {
993 switch(self::canProfilesDedupe($additionalProfileIds, $rgId)) {
994 case 0:
995 $dedupeTitle = 'Duplicate Matching Impossible';
996 if ($cantDedupe) {
997 $cantDedupe = ts("The selected profiles do not contain the fields necessary to match registrations with existing contacts. This means all anonymous registrations will result in a new contact.");
998 }
999 else {
1000 $cantDedupe = ts("The selected profiles do not contain the fields necessary to match additional participants with existing contacts. This means all additional participants will result in a new contact.");
1001 }
1002 break;
1003 case 1:
1004 if (!$cantDedupe) {
1005 $dedupeTitle = 'Duplicate Contacts Possible';
1006 $cantDedupe = ts("The selected profiles can collect enough information to match additional participants with existing contacts, but not all of the relevant fields are required. This may result in duplicate contacts.");
1007 }
1008 }
1009 }
1010 if ($cantDedupe) {
1011 CRM_Core_Session::setStatus($cantDedupe, $dedupeTitle, 'alert dedupenotify', array('expires' => 0));
1012 }
1013
1014 // Update tab "disabled" css class
1015 $this->ajaxResponse['tabValid'] = !empty($params['is_online_registration']);
1016
1017 parent::endPostProcess();
1018 }
1019 //end of function
1020
1021 /**
1022 * Return a descriptive name for the page, used in wizard header
1023 *
1024 * @return string
1025 * @access public
1026 */
1027 public function getTitle() {
1028 return ts('Online Registration');
1029 }
1030 }
1031