From a989f74b73a8fa7580b1d9509f26d8456625d245 Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Fri, 22 Sep 2023 10:05:49 +1200 Subject: [PATCH] Fix assigning of customGroup data to be more re-usable --- CRM/Core/BAO/CustomField.php | 62 +++++++++++++++++++ CRM/Event/Form/Participant.php | 41 +++--------- .../CRM/Event/Form/ParticipantTest.php | 14 +++++ 3 files changed, 86 insertions(+), 31 deletions(-) diff --git a/CRM/Core/BAO/CustomField.php b/CRM/Core/BAO/CustomField.php index 8d4bf6559e..79ef2f16f7 100644 --- a/CRM/Core/BAO/CustomField.php +++ b/CRM/Core/BAO/CustomField.php @@ -615,6 +615,7 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { ->addSelect('custom_group_id.extends_entity_column_value') ->addSelect('custom_group_id.is_active') ->addSelect('custom_group_id.name') + ->addSelect('custom_group_id.title') ->addSelect('custom_group_id.table_name') ->addSelect('custom_group_id.is_public'); if ($permissionType && !CRM_Core_Permission::customGroupAdmin()) { @@ -808,6 +809,67 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { return $field; } + /** + * Gets an array of custom fields that are public. + * + * @internal do not use from untested or external code - signature may change. + * + * This takes into account + * - the is_public setting on the Custom Group + * - the is_view permission on the field (these are generally suppressed). + * + * @param string $extends + * @param array $extendsEntity + * Keyed by name values from CRM_Core_BAO_CustomGroup::getExtendsEntityColumnIdOptions() + * Values can be an int or an array. + * eg ['ParticipantRole' = [1], 'ParticipantEventType' => 2], ['ParticipantEventName' => 3] + * @param int $permissionType + * + * @return array + * @throws \CRM_Core_Exception + */ + public static function getViewableCustomFields(string $extends, array $extendsEntity = [], $permissionType = CRM_Core_Permission::VIEW): array { + $entityFilters = []; + // Convert from ['ParticipantRole' = [1], 'ParticipantEventType' => 2], ['ParticipantEventName' => 3] + // to [1 => [1], 2 => [2], 3 = [3] + if (!empty($extendsEntity)) { + $entityColumns = CRM_Core_BAO_CustomGroup::getExtendsEntityColumnIdOptions(); + foreach ($entityColumns as $entityColumn) { + if (isset($extendsEntity[$entityColumn['name']])) { + $entityFilters[(int) $entityColumn['id']] = (array) $extendsEntity[$entityColumn['name']]; + foreach ($entityFilters[$entityColumn['id']] as &$value) { + // Cast to string because we don't want the calling function to have to worry + // but also the array intersect fails otherwise. + $value = (string) $value; + } + } + } + } + $cacheKey = $extends . $permissionType . CRM_Core_Config::domainID() . '_' . CRM_Core_I18n::getLocale() . substr(md5(json_encode($extendsEntity)), 0, 30); + if (!isset(\Civi::$statics[__CLASS__][__FUNCTION__][$cacheKey])) { + \Civi::$statics[__CLASS__][__FUNCTION__][$cacheKey] = []; + $allFields = CRM_Core_BAO_CustomField::getAllCustomFields($permissionType); + foreach ($allFields as $field) { + $entityValueMatches = array_intersect((array) $field['custom_group_id.extends_entity_column_value'], ($entityFilters[$field['custom_group_id.extends_entity_column_id']] ?? [])); + if ( + !$field['is_view'] + && $field['custom_group_id.is_public'] + && ( + !empty($entityValueMatches) + || empty($field['custom_group_id.extends_entity_column_id']) + ) + && ( + $field['custom_group_id.extends'] === $extends + || ($field['extends'] === 'Contact' && in_array($extends, ['Individual', 'Organization', 'Household'])) + ) + ) { + \Civi::$statics[__CLASS__][__FUNCTION__][$cacheKey][(int) $field['id']] = $field; + } + } + } + return \Civi::$statics[__CLASS__][__FUNCTION__][$cacheKey]; + } + /** * Add a custom field to an existing form. * diff --git a/CRM/Event/Form/Participant.php b/CRM/Event/Form/Participant.php index 2881e299b4..5c07b6d36a 100644 --- a/CRM/Event/Form/Participant.php +++ b/CRM/Event/Form/Participant.php @@ -2090,6 +2090,7 @@ INNER JOIN civicrm_price_field_value value ON ( value.id = lineItem.price_field_ * * @return array * @throws \CRM_Core_Exception + * @throws \Brick\Money\Exception\UnknownCurrencyException */ protected function sendReceipts($params, array $participants, $lineItem, $additionalParticipantDetails): array { $sent = []; @@ -2133,40 +2134,19 @@ INNER JOIN civicrm_price_field_value value ON ( value.id = lineItem.price_field_ } $customGroup = []; - //format submitted data - $customFieldsRole = []; - foreach ($this->getSubmittedValue('role_id') as $roleKey) { - $customFieldsRole = CRM_Utils_Array::crmArrayMerge(CRM_Core_BAO_CustomField::getFields('Participant', - FALSE, FALSE, $roleKey, $this->_roleCustomDataTypeID), $customFieldsRole); - } - $customFieldsEvent = CRM_Core_BAO_CustomField::getFields('Participant', - FALSE, - FALSE, - $this->getEventID(), - $this->_eventNameCustomDataTypeID - ); - $customFieldsEventType = CRM_Core_BAO_CustomField::getFields('Participant', - FALSE, - FALSE, - $this->_eventTypeId, - $this->_eventTypeCustomDataTypeID - ); - $customFields = CRM_Utils_Array::crmArrayMerge($customFieldsRole, - CRM_Core_BAO_CustomField::getFields('Participant', FALSE, FALSE, NULL, NULL, TRUE) - ); - $customFields = CRM_Utils_Array::crmArrayMerge($customFieldsEvent, $customFields); - $customFields = CRM_Utils_Array::crmArrayMerge($customFieldsEventType, $customFields); + $customFieldFilters = [ + 'ParticipantRole' => $this->getSubmittedValue('role_id'), + 'ParticipantEventName' => $this->getEventID(), + 'ParticipantEventType' => $this->getEventValue('event_type_id'), + ]; + $customFields = CRM_Core_BAO_CustomField::getViewableCustomFields('Participant', $customFieldFilters); foreach ($params['custom'] as $fieldID => $values) { foreach ($values as $fieldValue) { - $isPublic = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $fieldValue['custom_group_id'], 'is_public'); - if ($isPublic) { - $customFields[$fieldID]['id'] = $fieldID; - $formattedValue = CRM_Core_BAO_CustomField::displayValue($fieldValue['value'], $fieldID, $participants[0]->id); - $customGroup[$customFields[$fieldID]['groupTitle']][$customFields[$fieldID]['label']] = str_replace(' ', '', $formattedValue); - } + $formattedValue = CRM_Core_BAO_CustomField::displayValue($fieldValue['value'], $fieldID, $participants[0]->id); + $customGroup[$customFields[$fieldID]['custom_group_id.title']][$customFields[$fieldID]['label']] = str_replace(' ', '', $formattedValue); } } - + $this->assign('customGroup', $customGroup); foreach ($this->_contactIds as $num => $contactID) { // Retrieve the name and email of the contact - this will be the TO for receipt email [, $this->_contributorEmail, $this->_toDoNotEmail] = CRM_Contact_BAO_Contact::getContactDetails($contactID); @@ -2177,7 +2157,6 @@ INNER JOIN civicrm_price_field_value value ON ( value.id = lineItem.price_field_ $this->assign('isOnWaitlist', TRUE); } - $this->assign('customGroup', $customGroup); $this->assign('contactID', $contactID); $this->assign('participantID', $participants[$num]->id); diff --git a/tests/phpunit/CRM/Event/Form/ParticipantTest.php b/tests/phpunit/CRM/Event/Form/ParticipantTest.php index 84eefb9dce..d4832245ed 100644 --- a/tests/phpunit/CRM/Event/Form/ParticipantTest.php +++ b/tests/phpunit/CRM/Event/Form/ParticipantTest.php @@ -21,6 +21,7 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase { use FormTrait; use CRMTraits_Financial_OrderTrait; use CRMTraits_Financial_PriceSetTrait; + use CRMTraits_Custom_CustomDataTrait; public function tearDown(): void { $this->quickCleanUpFinancialEntities(); @@ -57,6 +58,19 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase { $this->assertStringContainsString('Volunteer, Speaker', $email); } + public function testSubmitWithCustomData(): void { + $this->createCustomGroupWithFieldOfType(['extends' => 'Participant', 'extends_entity_column_id' => 1, 'extends_entity_column_value' => CRM_Core_PseudoConstant::getKey('CRM_Event_BAO_Participant', 'role_id', 'Volunteer')]); + $email = $this->getForm([], [ + 'status_id' => 1, + 'register_date' => date('Ymd'), + 'send_receipt' => 1, + 'from_email_address' => 'admin@email.com', + 'role_id' => [CRM_Core_PseudoConstant::getKey('CRM_Event_BAO_Participant', 'role_id', 'Volunteer')], + $this->getCustomFieldName() => 'Random thing', + ])->postProcess()->getFirstMailBody(); + $this->assertStringContainsStrings($email, ['Enter text here', 'Random thing', 'Group with field text']); + } + /** * Test financial items pending transaction is later altered. * -- 2.25.1