Simplify CustomField::displayValue to expect an ID & have deprecated handline for...
authorEileen McNaughton <emcnaughton@wikimedia.org>
Wed, 20 Sep 2023 21:09:43 +0000 (09:09 +1200)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Thu, 21 Sep 2023 22:49:53 +0000 (10:49 +1200)
CRM/Core/BAO/CustomField.php
api/v3/CustomValue.php
tests/phpunit/CRM/Core/BAO/CustomQueryTest.php

index 1151a85560fc9491d37941249d784bd98b91f538..8d4bf6559e2d4171f5d41dc6cd2efce87b3dd03f 100644 (file)
@@ -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;
+  }
+
 }
index 252adeb0f68f03ee161e62f9a60a27b155bc3dc8..f2b7fb31945f9d69eb33350790eeb9a470d61e86 100644 (file)
@@ -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'])) {
index 678c32a30c0740d8392e818f5a6d94e453bc8366..79ed0f0c511aea8a663ea6f398aefa4f91f0cbb8 100644 (file)
@@ -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);
   }