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