Fix customField legacy handling in APIv3
authorColeman Watts <coleman@civicrm.org>
Fri, 4 Sep 2020 00:59:25 +0000 (20:59 -0400)
committerColeman Watts <coleman@civicrm.org>
Fri, 4 Sep 2020 23:32:43 +0000 (19:32 -0400)
13 files changed:
CRM/Core/DAO/CustomField.php
CRM/Upgrade/Incremental/sql/5.29.1.mysql.tpl [new file with mode: 0644]
api/v3/CustomField.php
tests/phpunit/CRM/Core/BAO/CustomFieldTest.php
tests/phpunit/CRM/Core/BAO/CustomQueryTest.php
tests/phpunit/CRM/Utils/Migrate/fixtures/Activity-text.xml
tests/phpunit/CRM/Utils/Migrate/fixtures/ActivityMeeting-text.xml
tests/phpunit/CRM/Utils/Migrate/fixtures/Contact-text.xml
tests/phpunit/CRM/Utils/Migrate/fixtures/Individual-text.xml
tests/phpunit/CRM/Utils/Migrate/fixtures/IndividualStudent-text.xml
tests/phpunit/api/v3/CustomFieldTest.php
tests/phpunit/api/v4/Action/CustomValueTest.php
xml/schema/Core/CustomField.xml

index 137fbf81a247caf18412772428856602a4df5ac5..6cae23bea07644c24a54dfb98f8802bf35e4cf49 100644 (file)
@@ -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 @@ class CRM_Core_DAO_CustomField extends CRM_Core_DAO {
           '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/Upgrade/Incremental/sql/5.29.1.mysql.tpl b/CRM/Upgrade/Incremental/sql/5.29.1.mysql.tpl
new file mode 100644 (file)
index 0000000..f51e009
--- /dev/null
@@ -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.';
index 1667721744b744ba6b86faa51e83ff707733553c..a9b664b0b59ac2a90952c4614aee5edabd361733 100644 (file)
@@ -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']);
index 42a74c2026938496245f2f8b5eadcda19064e209..bf3cdf38c8f29bd71e42b332e3becbc3d6dc9b01 100644 (file)
@@ -481,7 +481,7 @@ class CRM_Core_BAO_CustomFieldTest extends CiviUnitTestCase {
         '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 @@ class CRM_Core_BAO_CustomFieldTest extends CiviUnitTestCase {
         '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 @@ class CRM_Core_BAO_CustomFieldTest extends CiviUnitTestCase {
         '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 @@ class CRM_Core_BAO_CustomFieldTest extends CiviUnitTestCase {
         '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 @@ class CRM_Core_BAO_CustomFieldTest extends CiviUnitTestCase {
         '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 @@ class CRM_Core_BAO_CustomFieldTest extends CiviUnitTestCase {
         '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 @@ class CRM_Core_BAO_CustomFieldTest extends CiviUnitTestCase {
         '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 @@ class CRM_Core_BAO_CustomFieldTest extends CiviUnitTestCase {
         '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 @@ class CRM_Core_BAO_CustomFieldTest extends CiviUnitTestCase {
         '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 @@ class CRM_Core_BAO_CustomFieldTest extends CiviUnitTestCase {
         'text_length' => NULL,
         'options_per_line' => NULL,
         'is_search_range' => '0',
-        'serialize' => NULL,
+        'serialize' => 0,
         'pseudoconstant' => [
           'callback' => 'CRM_Core_SelectValues::boolean',
         ],
index acca0de169bff091a68c9a19c562c91baf1025b8..d1a103d53297d76b99452fdea6b42496754382b2 100644 (file)
@@ -85,7 +85,7 @@ class CRM_Core_BAO_CustomQueryTest extends CiviUnitTestCase {
       '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']));
 
   }
index b678d654d1ad840e91be4731c90d903187b972e1..20a73caf24a8c8b034db688eb0130d8410a58615 100644 (file)
@@ -31,6 +31,7 @@
       <is_active>1</is_active>
       <is_view>0</is_view>
       <column_name>name1_1</column_name>
+      <serialize>0</serialize>
       <in_selector>0</in_selector>
       <custom_group_name>example</custom_group_name>
     </CustomField>
index fe8d93eea5e28d53a89897ac9382f53470996260..58a45e824bd2d6d140e9ea8b292b8ad8ca653b30 100644 (file)
@@ -33,6 +33,7 @@
       <is_active>1</is_active>
       <is_view>0</is_view>
       <column_name>name1_1</column_name>
+      <serialize>0</serialize>
       <in_selector>0</in_selector>
       <custom_group_name>example</custom_group_name>
     </CustomField>
index c6fd5165228873bcc25a44886ce7b74eef07a9ee..22cb829ad8710cdecb2e1cabb8460598b3e3fe22 100644 (file)
@@ -31,6 +31,7 @@
       <is_active>1</is_active>
       <is_view>0</is_view>
       <column_name>name1_1</column_name>
+      <serialize>0</serialize>
       <in_selector>0</in_selector>
       <custom_group_name>example</custom_group_name>
     </CustomField>
index 59768ede169aef5538e096c6e1cdff555df77e41..ffdd76a9ef9ffcbea2186706cec4439ca001225f 100644 (file)
@@ -31,6 +31,7 @@
       <is_active>1</is_active>
       <is_view>0</is_view>
       <column_name>name1_1</column_name>
+      <serialize>0</serialize>
       <in_selector>0</in_selector>
       <custom_group_name>example</custom_group_name>
     </CustomField>
index 2a367d908e3933c4a645ca7c4c938522d054852d..6c7e06e692149f1d4196c805108cdd75d079db0f 100644 (file)
@@ -33,6 +33,7 @@
       <is_active>1</is_active>
       <is_view>0</is_view>
       <column_name>name1_1</column_name>
+      <serialize>0</serialize>
       <in_selector>0</in_selector>
       <custom_group_name>example</custom_group_name>
     </CustomField>
index 5d828378d20352671877133b4186851c5d5f5d48..8fc16468a1df084a3be4a4ac776da6cf1df8199a 100644 (file)
@@ -618,4 +618,64 @@ class api_v3_CustomFieldTest extends CiviUnitTestCase {
     $this->callAPISuccess('CustomField', 'create', $params);
   }
 
+  public function testLegacyHtmlType() {
+    $customGroup = $this->customGroupCreate([
+      'name' => 'testCustomGroup',
+      'title' => 'testCustomGroup',
+      'extends' => 'Individual',
+    ]);
+    $f1 = $this->callAPISuccess('CustomField', 'create', [
+      'label' => 'SingleSelect',
+      'custom_group_id' => 'testCustomGroup',
+      'data_type' => 'String',
+      'html_type' => 'Select',
+      'option_values' => [1 => 'One', 2 => 'Two'],
+    ]);
+    $f2 = $this->callAPISuccess('CustomField', 'create', [
+      'label' => 'CheckBoxes',
+      'custom_group_id' => 'testCustomGroup',
+      'data_type' => 'String',
+      'html_type' => 'CheckBox',
+      'option_values' => [1 => 'One', 2 => 'Two'],
+    ]);
+    $f3 = $this->callAPISuccess('CustomField', 'create', [
+      'label' => 'MultiSelect',
+      'custom_group_id' => 'testCustomGroup',
+      'data_type' => 'String',
+      'html_type' => 'Multi-Select',
+      'option_values' => [1 => 'One', 2 => 'Two'],
+    ]);
+
+    $result = $this->callAPISuccess('CustomField', 'get', [
+      'custom_group_id' => 'testCustomGroup',
+      'html_type' => 'Multi-Select',
+      'sequential' => 1,
+    ]);
+    $this->assertCount(1, $result['values']);
+    $this->assertEquals('MultiSelect', $result['values'][0]['label']);
+
+    $result = $this->callAPISuccess('CustomField', 'get', [
+      'custom_group_id' => 'testCustomGroup',
+      'html_type' => ['IN' => ['Multi-Select', 'CheckBox']],
+      'sequential' => 1,
+    ]);
+    $this->assertCount(2, $result['values']);
+
+    $result = $this->callAPISuccess('CustomField', 'get', [
+      'custom_group_id' => 'testCustomGroup',
+      'html_type' => 'Select',
+      'sequential' => 1,
+    ]);
+    $this->assertCount(1, $result['values']);
+    $this->assertEquals('SingleSelect', $result['values'][0]['label']);
+
+    $result = $this->callAPISuccess('CustomField', 'get', [
+      'custom_group_id' => 'testCustomGroup',
+      'html_type' => ['IN' => ['Select']],
+      'sequential' => 1,
+    ]);
+    $this->assertCount(1, $result['values']);
+    $this->assertEquals('SingleSelect', $result['values'][0]['label']);
+  }
+
 }
index 81edd46e2a7f078ac8655783ce1429a354654047..0b39e261731413989b2c651431632f9f46b54ada 100644 (file)
@@ -89,7 +89,7 @@ class CustomValueTest extends BaseCustomValueTest {
         'entity' => "Custom_$group",
         'data_type' => 'String',
         'fk_entity' => NULL,
-        'serialize' => NULL,
+        'serialize' => 0,
         'options' => $optionValues,
       ],
       [
@@ -109,7 +109,7 @@ class CustomValueTest extends BaseCustomValueTest {
         'entity' => "Custom_$group",
         'data_type' => 'String',
         'fk_entity' => NULL,
-        'serialize' => NULL,
+        'serialize' => 0,
       ],
       [
         'name' => 'id',
index 8d49adce76d0981a4a27814cd56938edae50b43c..44c632256010c3656ab9cd475ba9c5ea5d4cd713 100644 (file)
     <type>int unsigned</type>
     <title>Serialize</title>
     <length>255</length>
-    <comment>Serialization method - a non-null value indicates a multi-valued field.</comment>
+    <comment>Serialization method - a non-zero value indicates a multi-valued field.</comment>
     <pseudoconstant>
       <callback>CRM_Core_SelectValues::fieldSerialization</callback>
     </pseudoconstant>
     <add>5.27</add>
+    <required>true</required>
+    <default>0</default>
   </field>
   <field>
     <name>filter</name>