Api4 - Fix auto serialize array input for CheckBox/MultiSelect fields
authorColeman Watts <coleman@civicrm.org>
Thu, 26 Dec 2019 15:54:33 +0000 (10:54 -0500)
committerColeman Watts <coleman@civicrm.org>
Thu, 26 Dec 2019 16:40:58 +0000 (11:40 -0500)
CRM/Core/BAO/CustomField.php
CRM/Core/BAO/CustomValueTable.php
tests/phpunit/api/v4/Action/CustomValueTest.php

index 0607531c1bdf7b0839461d09be0cb989580abc2f..25bd3c1e9ab50a81be0bcc39e4217e6be7174266 100644 (file)
@@ -2595,15 +2595,15 @@ WHERE cf.id = %1 AND cg.is_multiple = 1";
   /**
    * Does this field store a serialized string?
    *
-   * @param array $field
+   * @param array|object $field
    *
    * @return bool
    */
   public static function isSerialized($field) {
     // Fields retrieved via api are an array, or from the dao are an object. We'll accept either.
-    $field = (array) $field;
+    $html_type = is_object($field) ? $field->html_type : $field['html_type'];
     // FIXME: Currently the only way to know if data is serialized is by looking at the html_type. It would be cleaner to decouple this.
-    return ($field['html_type'] == 'CheckBox' || strpos($field['html_type'], 'Multi') !== FALSE);
+    return ($html_type === 'CheckBox' || strpos($html_type, 'Multi') !== FALSE);
   }
 
   /**
index de1f8613ee420318c39ba022b3745b75ff84dd0e..0b352b4c097b6dad02c151f8738ce9aa6edac362 100644 (file)
@@ -573,6 +573,7 @@ SELECT cg.table_name  as table_name ,
        cg.extends     as extends,
        cf.column_name as column_name,
        cf.id          as cf_id      ,
+       cf.html_type   as html_type  ,
        cf.data_type   as data_type
 FROM   civicrm_custom_group cg,
        civicrm_custom_field cf
@@ -586,6 +587,10 @@ AND    cf.id IN ( $fieldIDList )
     while ($dao->fetch()) {
       $dataType = $dao->data_type == 'Date' ? 'Timestamp' : $dao->data_type;
       foreach ($fieldValues[$dao->cf_id] as $fieldValue) {
+        // Serialize array values
+        if (is_array($fieldValue['value']) && CRM_Core_BAO_CustomField::isSerialized($dao)) {
+          $fieldValue['value'] = CRM_Utils_Array::implodePadded($fieldValue['value']);
+        }
         // Format null values correctly
         if ($fieldValue['value'] === NULL || $fieldValue['value'] === '') {
           switch ($dataType) {
index a0b590f1968f66029cb993351b03879090d57035..9713ee1cf8736cc15c8745219bddfbcf48d5443e 100644 (file)
@@ -41,6 +41,7 @@ class CustomValueTest extends BaseCustomValueTest {
 
     $group = uniqid('groupc');
     $colorField = uniqid('colorc');
+    $multiField = uniqid('chkbx');
     $textField = uniqid('txt');
 
     $customGroup = CustomGroup::create()
@@ -60,6 +61,15 @@ class CustomValueTest extends BaseCustomValueTest {
       ->addValue('data_type', 'String')
       ->execute();
 
+    CustomField::create()
+      ->setCheckPermissions(FALSE)
+      ->addValue('label', $multiField)
+      ->addValue('options', $optionValues)
+      ->addValue('custom_group_id', $customGroup['id'])
+      ->addValue('html_type', 'CheckBox')
+      ->addValue('data_type', 'String')
+      ->execute();
+
     CustomField::create()
       ->setCheckPermissions(FALSE)
       ->addValue('label', $textField)
@@ -80,22 +90,31 @@ class CustomValueTest extends BaseCustomValueTest {
     $fields = CustomValue::getFields($group)->execute();
     $expectedResult = [
       [
-        'custom_field_id' => 1,
         'custom_group' => $group,
         'name' => $colorField,
         'title' => $colorField,
         'entity' => "Custom_$group",
         'data_type' => 'String',
         'fk_entity' => NULL,
+        'serialize' => NULL,
+      ],
+      [
+        'custom_group' => $group,
+        'name' => $multiField,
+        'title' => $multiField,
+        'entity' => "Custom_$group",
+        'data_type' => 'String',
+        'fk_entity' => NULL,
+        'serialize' => 1,
       ],
       [
-        'custom_field_id' => 2,
         'custom_group' => $group,
         'name' => $textField,
         'title' => $textField,
         'entity' => "Custom_$group",
         'data_type' => 'String',
         'fk_entity' => NULL,
+        'serialize' => NULL,
       ],
       [
         'name' => 'id',
@@ -122,11 +141,11 @@ class CustomValueTest extends BaseCustomValueTest {
     // CASE 1: Test CustomValue::create
     // Create two records for a single contact and using CustomValue::get ensure that two records are created
     CustomValue::create($group)
-      ->addValue($colorField, 'Green')
+      ->addValue($colorField, 'g')
       ->addValue("entity_id", $this->contactID)
       ->execute();
     CustomValue::create($group)
-      ->addValue($colorField, 'Red')
+      ->addValue($colorField, 'r')
       ->addValue("entity_id", $this->contactID)
       ->execute();
     // fetch custom values using API4 CustomValue::get
@@ -137,12 +156,12 @@ class CustomValueTest extends BaseCustomValueTest {
     $expectedResult = [
       [
         'id' => 1,
-        $colorField => 'Green',
+        $colorField => 'g',
         'entity_id' => $this->contactID,
       ],
       [
         'id' => 2,
-        $colorField => 'Red',
+        $colorField => 'r',
         'entity_id' => $this->contactID,
       ],
     ];
@@ -154,10 +173,10 @@ class CustomValueTest extends BaseCustomValueTest {
     }
 
     // CASE 2: Test CustomValue::update
-    // Update a records whose id is 1 and change the custom field (name = Color) value to 'White' from 'Green'
+    // Update a records whose id is 1 and change the custom field (name = Color) value to 'Blue' from 'Green'
     CustomValue::update($group)
       ->addWhere("id", "=", 1)
-      ->addValue($colorField, 'White')
+      ->addValue($colorField, 'b')
       ->execute();
 
     // ensure that the value is changed for id = 1
@@ -165,7 +184,7 @@ class CustomValueTest extends BaseCustomValueTest {
       ->addWhere("id", "=", 1)
       ->execute()
       ->first()[$colorField];
-    $this->assertEquals('White', $color);
+    $this->assertEquals('b', $color);
 
     // CASE 3: Test CustomValue::replace
     // create a second contact which will be used to replace the custom values, created earlier
@@ -177,9 +196,9 @@ class CustomValueTest extends BaseCustomValueTest {
       ->execute()
       ->first()['id'];
     // Replace all the records which was created earlier with entity_id = first contact
-    //  with custom record [$colorField => 'Rainbow', 'entity_id' => $secondContactID]
+    //  with custom record [$colorField => 'g', 'entity_id' => $secondContactID]
     CustomValue::replace($group)
-      ->setRecords([[$colorField => 'Rainbow', 'entity_id' => $secondContactID]])
+      ->setRecords([[$colorField => 'g', $multiField => ['r', 'g'], 'entity_id' => $secondContactID]])
       ->addWhere('entity_id', '=', $this->contactID)
       ->execute();
 
@@ -190,7 +209,8 @@ class CustomValueTest extends BaseCustomValueTest {
     $expectedResult = [
       [
         'id' => 3,
-        $colorField => 'Rainbow',
+        $colorField => 'g',
+        $multiField => ['r', 'g'],
         'entity_id' => $secondContactID,
       ],
     ];