From 3766bd367a2e7f4d49a6599d764898c01bd81705 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Thu, 26 Dec 2019 10:54:33 -0500 Subject: [PATCH] Api4 - Fix auto serialize array input for CheckBox/MultiSelect fields --- CRM/Core/BAO/CustomField.php | 6 +-- CRM/Core/BAO/CustomValueTable.php | 5 +++ .../phpunit/api/v4/Action/CustomValueTest.php | 44 ++++++++++++++----- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/CRM/Core/BAO/CustomField.php b/CRM/Core/BAO/CustomField.php index 0607531c1b..25bd3c1e9a 100644 --- a/CRM/Core/BAO/CustomField.php +++ b/CRM/Core/BAO/CustomField.php @@ -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); } /** diff --git a/CRM/Core/BAO/CustomValueTable.php b/CRM/Core/BAO/CustomValueTable.php index de1f8613ee..0b352b4c09 100644 --- a/CRM/Core/BAO/CustomValueTable.php +++ b/CRM/Core/BAO/CustomValueTable.php @@ -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) { diff --git a/tests/phpunit/api/v4/Action/CustomValueTest.php b/tests/phpunit/api/v4/Action/CustomValueTest.php index a0b590f196..9713ee1cf8 100644 --- a/tests/phpunit/api/v4/Action/CustomValueTest.php +++ b/tests/phpunit/api/v4/Action/CustomValueTest.php @@ -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, ], ]; -- 2.25.1