diff --git a/CRM/Core/DAO/CustomField.php b/CRM/Core/DAO/CustomField.php
index 137fbf81a247..6cae23bea076 100644
--- a/CRM/Core/DAO/CustomField.php
+++ b/CRM/Core/DAO/CustomField.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Core/CustomField.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:200b28277fc9e025b42d3f3e45fde020)
+ * (GenCodeChecksum:1acb9b3538bd3005b99e6af6d9ec062f)
*/
/**
@@ -227,7 +227,7 @@ class CRM_Core_DAO_CustomField extends CRM_Core_DAO {
public $option_group_id;
/**
- * Serialization method - a non-null value indicates a multi-valued field.
+ * Serialization method - a non-zero value indicates a multi-valued field.
*
* @var int
*/
@@ -688,8 +688,10 @@ public static function &fields() {
'name' => 'serialize',
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Serialize'),
- 'description' => ts('Serialization method - a non-null value indicates a multi-valued field.'),
+ 'description' => ts('Serialization method - a non-zero value indicates a multi-valued field.'),
+ 'required' => TRUE,
'where' => 'civicrm_custom_field.serialize',
+ 'default' => '0',
'table_name' => 'civicrm_custom_field',
'entity' => 'CustomField',
'bao' => 'CRM_Core_BAO_CustomField',
diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php
index d8fd267310cd..69827f16192f 100644
--- a/CRM/Dedupe/Merger.php
+++ b/CRM/Dedupe/Merger.php
@@ -541,6 +541,12 @@ public static function moveContactBelongings($mergeHandler, $tables, $tableOpera
continue;
}
+ if ($table === 'civicrm_dashboard_contact') {
+ $sqls[] = "UPDATE IGNORE civicrm_dashboard_contact SET contact_id = $mainId WHERE contact_id = $otherId";
+ $sqls[] = "DELETE FROM civicrm_dashboard_contact WHERE contact_id = $otherId";
+ continue;
+ }
+
if ($table === 'civicrm_dedupe_exception') {
$sqls[] = "UPDATE IGNORE civicrm_dedupe_exception SET contact_id1 = $mainId WHERE contact_id1 = $otherId";
$sqls[] = "UPDATE IGNORE civicrm_dedupe_exception SET contact_id2 = $mainId WHERE contact_id2 = $otherId";
diff --git a/CRM/Upgrade/Incremental/sql/5.29.1.mysql.tpl b/CRM/Upgrade/Incremental/sql/5.29.1.mysql.tpl
new file mode 100644
index 000000000000..f51e009f0dc4
--- /dev/null
+++ b/CRM/Upgrade/Incremental/sql/5.29.1.mysql.tpl
@@ -0,0 +1,7 @@
+{* file to handle db changes in 5.29.1 during upgrade *}
+
+UPDATE `civicrm_custom_field` SET `serialize` = 0 WHERE `serialize` IS NULL;
+
+ALTER TABLE `civicrm_custom_field`
+CHANGE COLUMN `serialize`
+`serialize` int unsigned NOT NULL DEFAULT 0 COMMENT 'Serialization method - a non-zero value indicates a multi-valued field.';
diff --git a/api/v3/CustomField.php b/api/v3/CustomField.php
index 1667721744b7..a9b664b0b59a 100644
--- a/api/v3/CustomField.php
+++ b/api/v3/CustomField.php
@@ -122,18 +122,45 @@ function civicrm_api3_custom_field_delete($params) {
* @return array
*/
function civicrm_api3_custom_field_get($params) {
- if (CRM_Core_BAO_Domain::isDBVersionAtLeast('5.27.alpha1') && ($params['legacy_html_type'] ?? TRUE) && !empty($params['return'])) {
- if (is_array($params['return'])) {
+ // Legacy handling for serialize property
+ $handleLegacy = (($params['legacy_html_type'] ?? !isset($params['serialize'])) && CRM_Core_BAO_Domain::isDBVersionAtLeast('5.27.alpha1'));
+ if ($handleLegacy && !empty($params['return'])) {
+ if (!is_array($params['return'])) {
+ $params['return'] = explode(',', str_replace(' ', '', $params['return']));
+ }
+ if (!in_array('serialize', $params['return'])) {
$params['return'][] = 'serialize';
}
- elseif (is_string($params['return'])) {
- $params['return'] .= ',serialize';
+ }
+ if ($handleLegacy && !empty($params['html_type'])) {
+ $serializedTypes = ['CheckBox', 'Multi-Select', 'Multi-Select Country', 'Multi-Select State/Province'];
+ if (is_string($params['html_type'])) {
+ if (strpos($params['html_type'], 'Multi-Select') === 0) {
+ $params['html_type'] = str_replace('Multi-Select', 'Select', $params['html_type']);
+ $params['serialize'] = 1;
+ }
+ elseif (!in_array($params['html_type'], $serializedTypes)) {
+ $params['serialize'] = 0;
+ }
+ }
+ elseif (is_array($params['html_type']) && !empty($params['html_type']['IN'])) {
+ $excludeNonSerialized = !array_diff($params['html_type']['IN'], $serializedTypes);
+ $onlyNonSerialized = !array_intersect($params['html_type']['IN'], $serializedTypes);
+ $params['html_type']['IN'] = array_map(function($val) {
+ return str_replace('Multi-Select', 'Select', $val);
+ }, $params['html_type']['IN']);
+ if ($excludeNonSerialized) {
+ $params['serialize'] = 1;
+ }
+ if ($onlyNonSerialized) {
+ $params['serialize'] = 0;
+ }
}
}
$results = _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params);
- if (($params['legacy_html_type'] ?? TRUE) && !empty($results['values']) && is_array($results['values'])) {
+ if ($handleLegacy && !empty($results['values']) && is_array($results['values']) && !isset($params['serialize'])) {
foreach ($results['values'] as $id => $result) {
if (!empty($result['serialize']) && !empty($result['html_type'])) {
$results['values'][$id]['html_type'] = str_replace('Select', 'Multi-Select', $result['html_type']);
diff --git a/tests/phpunit/CRM/Core/BAO/CustomFieldTest.php b/tests/phpunit/CRM/Core/BAO/CustomFieldTest.php
index 42a74c202693..bf3cdf38c8f2 100644
--- a/tests/phpunit/CRM/Core/BAO/CustomFieldTest.php
+++ b/tests/phpunit/CRM/Core/BAO/CustomFieldTest.php
@@ -481,7 +481,7 @@ public function testGetFieldsForImport() {
'where' => 'civicrm_value_custom_group_' . $customGroupID . '.' . $this->getCustomFieldColumnName('country'),
'extends_table' => 'civicrm_contact',
'search_table' => 'contact_a',
- 'serialize' => NULL,
+ 'serialize' => 0,
'pseudoconstant' => [
'table' => 'civicrm_country',
'keyColumn' => 'id',
@@ -559,7 +559,7 @@ public function testGetFieldsForImport() {
'where' => 'civicrm_value_custom_group_' . $customGroupID . '.my_file_' . $this->getCustomFieldID('file'),
'extends_table' => 'civicrm_contact',
'search_table' => 'contact_a',
- 'serialize' => NULL,
+ 'serialize' => 0,
],
$this->getCustomFieldName('text') => [
'name' => $this->getCustomFieldName('text'),
@@ -593,7 +593,7 @@ public function testGetFieldsForImport() {
'extends_table' => 'civicrm_contact',
'search_table' => 'contact_a',
'maxlength' => 300,
- 'serialize' => NULL,
+ 'serialize' => 0,
],
$this->getCustomFieldName('select_string') => [
'name' => $this->getCustomFieldName('select_string'),
@@ -626,7 +626,7 @@ public function testGetFieldsForImport() {
'where' => 'civicrm_value_custom_group_' . $customGroupID . '.pick_color_' . $this->getCustomFieldID('select_string'),
'extends_table' => 'civicrm_contact',
'search_table' => 'contact_a',
- 'serialize' => NULL,
+ 'serialize' => 0,
'pseudoconstant' => [
'optionGroupName' => $this->callAPISuccessGetValue('CustomField', ['id' => $this->getCustomFieldID('select_string'), 'return' => 'option_group_id.name']),
'optionEditPath' => 'civicrm/admin/options/' . $this->callAPISuccessGetValue('CustomField', ['id' => $this->getCustomFieldID('select_string'), 'return' => 'option_group_id.name']),
@@ -663,7 +663,7 @@ public function testGetFieldsForImport() {
'where' => 'civicrm_value_custom_group_' . $customGroupID . '.test_date_' . $this->getCustomFieldID('select_date'),
'extends_table' => 'civicrm_contact',
'search_table' => 'contact_a',
- 'serialize' => NULL,
+ 'serialize' => 0,
],
$this->getCustomFieldName('link') => [
'name' => $this->getCustomFieldName('link'),
@@ -696,7 +696,7 @@ public function testGetFieldsForImport() {
'where' => 'civicrm_value_custom_group_' . $customGroupID . '.test_link_' . $this->getCustomFieldID('link'),
'extends_table' => 'civicrm_contact',
'search_table' => 'contact_a',
- 'serialize' => NULL,
+ 'serialize' => 0,
],
$this->getCustomFieldName('int') => [
'name' => $this->getCustomFieldName('int'),
@@ -729,7 +729,7 @@ public function testGetFieldsForImport() {
'where' => 'civicrm_value_custom_group_' . $customGroupID . '.' . $this->getCustomFieldColumnName('int'),
'extends_table' => 'civicrm_contact',
'search_table' => 'contact_a',
- 'serialize' => NULL,
+ 'serialize' => 0,
],
$this->getCustomFieldName('contact_reference') => [
'name' => $this->getCustomFieldName('contact_reference'),
@@ -762,7 +762,7 @@ public function testGetFieldsForImport() {
'where' => 'civicrm_value_custom_group_' . $customGroupID . '.' . $this->getCustomFieldColumnName('contact_reference'),
'extends_table' => 'civicrm_contact',
'search_table' => 'contact_a',
- 'serialize' => NULL,
+ 'serialize' => 0,
],
$this->getCustomFieldName('state') => [
'name' => $this->getCustomFieldName('state'),
@@ -788,7 +788,7 @@ public function testGetFieldsForImport() {
'where' => 'civicrm_value_custom_group_' . $customGroupID . '.' . $this->getCustomFieldColumnName('state'),
'extends_table' => 'civicrm_contact',
'search_table' => 'contact_a',
- 'serialize' => NULL,
+ 'serialize' => 0,
'pseudoconstant' => [
'table' => 'civicrm_state_province',
'keyColumn' => 'id',
@@ -871,7 +871,7 @@ public function testGetFieldsForImport() {
'text_length' => NULL,
'options_per_line' => NULL,
'is_search_range' => '0',
- 'serialize' => NULL,
+ 'serialize' => 0,
'pseudoconstant' => [
'callback' => 'CRM_Core_SelectValues::boolean',
],
diff --git a/tests/phpunit/CRM/Core/BAO/CustomQueryTest.php b/tests/phpunit/CRM/Core/BAO/CustomQueryTest.php
index acca0de169bf..d1a103d53297 100644
--- a/tests/phpunit/CRM/Core/BAO/CustomQueryTest.php
+++ b/tests/phpunit/CRM/Core/BAO/CustomQueryTest.php
@@ -85,7 +85,7 @@ public function testSearchCustomDataDateRelative() {
'type' => 4,
'where' => 'civicrm_value_testsearchcus_' . $ids['custom_group_id'] . '.date_field_' . $dateCustomField['id'],
'import' => 1,
- 'serialize' => NULL,
+ 'serialize' => 0,
], $queryObj->getFieldSpec('custom_' . $dateCustomField['id']));
}
diff --git a/tests/phpunit/CRM/Utils/Migrate/fixtures/Activity-text.xml b/tests/phpunit/CRM/Utils/Migrate/fixtures/Activity-text.xml
index b678d654d1ad..20a73caf24a8 100644
--- a/tests/phpunit/CRM/Utils/Migrate/fixtures/Activity-text.xml
+++ b/tests/phpunit/CRM/Utils/Migrate/fixtures/Activity-text.xml
@@ -31,6 +31,7 @@