From 9a0cb9fcc7d30e61d0535e2421bf1de84f81189b Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Thu, 21 Sep 2023 09:09:43 +1200 Subject: [PATCH] Simplify CustomField::displayValue to expect an ID & have deprecated handline for anything else --- CRM/Core/BAO/CustomField.php | 135 +++++++++++------- api/v3/CustomValue.php | 2 +- .../phpunit/CRM/Core/BAO/CustomQueryTest.php | 4 +- 3 files changed, 85 insertions(+), 56 deletions(-) diff --git a/CRM/Core/BAO/CustomField.php b/CRM/Core/BAO/CustomField.php index 1151a85560..8d4bf6559e 100644 --- a/CRM/Core/BAO/CustomField.php +++ b/CRM/Core/BAO/CustomField.php @@ -286,45 +286,23 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { } /** - * @param string $context + * @param string|null $context * @return array|bool */ - public function getOptions($context = NULL) { - CRM_Core_DAO::buildOptionsContext($context); + public function getOptions(?string $context = NULL) { if (!$this->id) { return FALSE; } - $cacheKey = "CRM_Core_BAO_CustomField_getOptions_{$this->id}_$context"; - $cache = CRM_Utils_Cache::singleton(); - $options = $cache->get($cacheKey); - if (!isset($options)) { - if (!$this->data_type || !$this->custom_group_id) { - $this->find(TRUE); - } - - // This will hold the list of options in format key => label - $options = []; - - if (!empty($this->option_group_id)) { - $options = CRM_Core_OptionGroup::valuesByID( - $this->option_group_id, FALSE, FALSE, FALSE, $context == 'validate' ? 'name' : 'label', !($context == 'validate' || $context == 'get') - ); - } - elseif ($this->data_type === 'StateProvince') { - $options = CRM_Core_PseudoConstant::stateProvince(); - } - elseif ($this->data_type === 'Country') { - $options = $context == 'validate' ? CRM_Core_PseudoConstant::countryIsoCode() : CRM_Core_PseudoConstant::country(); - } - elseif ($this->data_type === 'Boolean') { - $options = $context == 'validate' ? [0, 1] : CRM_Core_SelectValues::boolean(); - } - CRM_Utils_Hook::customFieldOptions($this->id, $options, FALSE); - CRM_Utils_Hook::fieldOptions($this->getEntity(), "custom_{$this->id}", $options, ['context' => $context]); - $cache->set($cacheKey, $options); + if (!$this->data_type || !$this->custom_group_id) { + $this->find(TRUE); } - return $options; + $id = (int) $this->id; + $dataType = $this->data_type; + $optionGroupID = $this->option_group_id ? (int) $this->option_group_id : NULL; + $entity = $this->getEntity(); + + return self::getFieldOptions($id, $optionGroupID, $dataType, $entity, $context); } /** @@ -810,6 +788,26 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { return $field; } + /** + * Use the cache to get all values of a specific custom field. + * + * @param int $id + * The custom field ID. + * @param int|false $permissionType + * + * @return array + * The field object. + * @throws CRM_Core_Exception + */ + public static function getField(int $id, $permissionType = FALSE): array { + $field = self::getAllCustomFields($permissionType)[$id]; + // @todo - on the fence about caching these in the cache for all custom fields. The down side is the + // cache array could get really big & serializing & un-serializing big arrays is expensive. + $entity = in_array($field['custom_group_id.extends'], CRM_Contact_BAO_ContactType::basicTypes(TRUE), TRUE) ? 'Contact' : $field['custom_group_id.extends']; + $field['options'] = self::getFieldOptions($field['id'], $field['option_group_id'], $field['data_type'], $entity); + return $field; + } + /** * Add a custom field to an existing form. * @@ -1166,31 +1164,24 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { /** * @param string|int|array|null $value - * @param CRM_Core_BAO_CustomField|int|array|string $field - * @param int $entityId + * @param int $fieldID + * @param ?int $entityID + * Entity ID is used a a proxy for context + * - In the context of displaying a profile, show file/image + * - In other contexts show a paperclip icon. * * @return string - * - * @throws \CRM_Core_Exception + * @throws \CRM_Core_Exception|\Brick\Money\Exception\UnknownCurrencyException */ - public static function displayValue($value, $field, $entityId = NULL) { - $field = is_array($field) ? $field['id'] : $field; - $fieldId = is_object($field) ? $field->id : (int) str_replace('custom_', '', $field); - - if (!$fieldId) { - throw new CRM_Core_Exception('CRM_Core_BAO_CustomField::displayValue requires a field id'); - } - - if (!is_a($field, 'CRM_Core_BAO_CustomField')) { - $field = self::getFieldObject($fieldId); + public static function displayValue($value, $fieldID, $entityID = NULL) { + if (!is_numeric($fieldID)) { + // Deprecated support for a non-id value. + $fieldID = is_object($fieldID) ? $fieldID->id : (int) str_replace('custom_', '', $fieldID); } - - $fieldInfo = ['options' => $field->getOptions()] + (array) $field; - - $displayValue = self::formatDisplayValue($value, $fieldInfo, $entityId); - + $fieldInfo = self::getField($fieldID); + $displayValue = self::formatDisplayValue($value, $fieldInfo, $entityID); // Call hook to alter display value. - CRM_Utils_Hook::alterCustomFieldDisplayValue($displayValue, $value, $entityId, $fieldInfo); + CRM_Utils_Hook::alterCustomFieldDisplayValue($displayValue, $value, $entityID, $fieldInfo); return $displayValue; } @@ -2915,4 +2906,44 @@ WHERE cf.id = %1 AND cg.is_multiple = 1"; return $params; } + /** + * @param int $id + * @param int|null $optionGroupID + * @param string $dataType + * @param string $entity + * @param string|null $context + * + * @return array|int[]|mixed|null + * @throws \CRM_Core_Exception + */ + private static function getFieldOptions(int $id, ?int $optionGroupID, string $dataType, string $entity, ?string $context = NULL): array { + CRM_Core_DAO::buildOptionsContext($context); + $cacheKey = "CRM_Core_BAO_CustomField_getOptions_{$id}_$context"; + $cache = CRM_Utils_Cache::singleton(); + $options = $cache->get($cacheKey); + if (!isset($options)) { + // This will hold the list of options in format key => label + $options = []; + + if ($optionGroupID) { + $options = CRM_Core_OptionGroup::valuesByID( + $optionGroupID, FALSE, FALSE, FALSE, $context === 'validate' ? 'name' : 'label', !($context === 'validate' || $context === 'get') + ); + } + elseif ($dataType === 'StateProvince') { + $options = CRM_Core_PseudoConstant::stateProvince(); + } + elseif ($dataType === 'Country') { + $options = $context === 'validate' ? CRM_Core_PseudoConstant::countryIsoCode() : CRM_Core_PseudoConstant::country(); + } + elseif ($dataType === 'Boolean') { + $options = $context === 'validate' ? [0, 1] : CRM_Core_SelectValues::boolean(); + } + CRM_Utils_Hook::customFieldOptions($id, $options); + CRM_Utils_Hook::fieldOptions($entity, "custom_{$id}", $options, ['context' => $context]); + $cache->set($cacheKey, $options); + } + return $options; + } + } diff --git a/api/v3/CustomValue.php b/api/v3/CustomValue.php index 252adeb0f6..f2b7fb3194 100644 --- a/api/v3/CustomValue.php +++ b/api/v3/CustomValue.php @@ -360,7 +360,7 @@ function civicrm_api3_custom_value_gettree($params) { if (!empty($fieldInfo['customValue'])) { $field['value'] = CRM_Utils_Array::first($fieldInfo['customValue']); if (!$toReturn['custom_value'] || in_array('display', $toReturn['custom_value'])) { - $field['value']['display'] = CRM_Core_BAO_CustomField::displayValue($field['value']['data'], $fieldInfo); + $field['value']['display'] = CRM_Core_BAO_CustomField::displayValue($field['value']['data'], $fieldInfo['id']); } foreach (array_keys($field['value']) as $key) { if ($toReturn['custom_value'] && !in_array($key, $toReturn['custom_value'])) { diff --git a/tests/phpunit/CRM/Core/BAO/CustomQueryTest.php b/tests/phpunit/CRM/Core/BAO/CustomQueryTest.php index 678c32a30c..79ed0f0c51 100644 --- a/tests/phpunit/CRM/Core/BAO/CustomQueryTest.php +++ b/tests/phpunit/CRM/Core/BAO/CustomQueryTest.php @@ -163,8 +163,6 @@ class CRM_Core_BAO_CustomQueryTest extends CiviUnitTestCase { /** * Test filtering by relative custom data dates. - * - * @throws \CRM_Core_Exception */ public function testSearchCustomDataDateFromTo(): void { $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, 'ContactTestTest'); @@ -194,7 +192,7 @@ class CRM_Core_BAO_CustomQueryTest extends CiviUnitTestCase { $this->assertEquals($queryObj->_qill[0][0], "date field BETWEEN 'June 6th, 2014 12:00 AM AND June 6th, 2015 11:59 PM'"); //CRM-17236 - Test custom date is correctly displayed without time. - $formattedValue = CRM_Core_BAO_CustomField::displayValue(date('Ymdhms'), $dateCustomField['id']); + $formattedValue = CRM_Core_BAO_CustomField::displayValue(date('Ymdhms'), (int) $dateCustomField['id']); $this->assertEquals(date('m/d/Y'), $formattedValue); } -- 2.25.1