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