APIv4 - Fix saving NULL as custom field value
authorColeman Watts <coleman@civicrm.org>
Mon, 27 Dec 2021 14:15:36 +0000 (09:15 -0500)
committerColeman Watts <coleman@civicrm.org>
Mon, 27 Dec 2021 14:15:36 +0000 (09:15 -0500)
Fixes dev/report#89

Civi/Api4/Generic/Traits/DAOActionTrait.php
tests/phpunit/api/v4/Action/BasicCustomFieldTest.php

index 46120cd40beb57534d678c5cbaba7d038bd8bc10..8f00ba7ee0f35b1ccc9ac236e4f8103f1d900f96 100644 (file)
@@ -257,43 +257,44 @@ trait DAOActionTrait {
         continue;
       }
 
-      // todo are we sure we don't want to allow setting to NULL? need to test
-      if (NULL !== $value) {
+      // Null and empty string are interchangeable as far as the custom bao understands
+      if (NULL === $value) {
+        $value = '';
+      }
 
-        if ($field['suffix']) {
-          $options = FormattingUtil::getPseudoconstantList($field, $name, $params, $this->getActionName());
-          $value = FormattingUtil::replacePseudoconstant($options, $value, TRUE);
-        }
+      if ($field['suffix']) {
+        $options = FormattingUtil::getPseudoconstantList($field, $name, $params, $this->getActionName());
+        $value = FormattingUtil::replacePseudoconstant($options, $value, TRUE);
+      }
 
-        if ($field['html_type'] === 'CheckBox') {
-          // this function should be part of a class
-          formatCheckBoxField($value, 'custom_' . $field['id'], $this->getEntityName());
-        }
+      if ($field['html_type'] === 'CheckBox') {
+        // this function should be part of a class
+        formatCheckBoxField($value, 'custom_' . $field['id'], $this->getEntityName());
+      }
 
-        // Match contact id to strings like "user_contact_id"
-        // FIXME handle arrays for multi-value contact reference fields, etc.
-        if ($field['data_type'] === 'ContactReference' && is_string($value) && !is_numeric($value)) {
-          // FIXME decouple from v3 API
-          require_once 'api/v3/utils.php';
-          $value = \_civicrm_api3_resolve_contactID($value);
-          if ('unknown-user' === $value) {
-            throw new \API_Exception("\"{$field['name']}\" \"{$value}\" cannot be resolved to a contact ID", 2002, ['error_field' => $field['name'], "type" => "integer"]);
-          }
+      // Match contact id to strings like "user_contact_id"
+      // FIXME handle arrays for multi-value contact reference fields, etc.
+      if ($field['data_type'] === 'ContactReference' && is_string($value) && !is_numeric($value)) {
+        // FIXME decouple from v3 API
+        require_once 'api/v3/utils.php';
+        $value = \_civicrm_api3_resolve_contactID($value);
+        if ('unknown-user' === $value) {
+          throw new \API_Exception("\"{$field['name']}\" \"{$value}\" cannot be resolved to a contact ID", 2002, ['error_field' => $field['name'], "type" => "integer"]);
         }
-
-        \CRM_Core_BAO_CustomField::formatCustomField(
-          $field['id'],
-          $customParams,
-          $value,
-          $field['custom_group_id.extends'],
-          // todo check when this is needed
-          NULL,
-          $entityId,
-          FALSE,
-          $this->getCheckPermissions(),
-          TRUE
-        );
       }
+
+      \CRM_Core_BAO_CustomField::formatCustomField(
+        $field['id'],
+        $customParams,
+        $value,
+        $field['custom_group_id.extends'],
+        // todo check when this is needed
+        NULL,
+        $entityId,
+        FALSE,
+        $this->getCheckPermissions(),
+        TRUE
+      );
     }
 
     $params['custom'] = $customParams ?: NULL;
index de2edf923cc7ae3da30be8f22d55090f2fda860d..240ce3a9432f0ffe74e283f5e7f500f72c8e7d1e 100644 (file)
@@ -84,6 +84,18 @@ class BasicCustomFieldTest extends BaseCustomValueTest {
       ->first();
 
     $this->assertEquals('Blue', $contact['MyIndividualFields.FavColor']);
+
+    // Try setting to null
+    Contact::update()
+      ->addWhere('id', '=', $contactId)
+      ->addValue('MyIndividualFields.FavColor', NULL)
+      ->execute();
+    $contact = Contact::get(FALSE)
+      ->addSelect('MyIndividualFields.FavColor')
+      ->addWhere('id', '=', $contactId)
+      ->execute()
+      ->first();
+    $this->assertEquals(NULL, $contact['MyIndividualFields.FavColor']);
   }
 
   public function testWithTwoFields() {