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