diff --git a/CRM/Core/BAO/CustomField.php b/CRM/Core/BAO/CustomField.php
index c67b60f7a9c5..55e1b786bbc7 100644
--- a/CRM/Core/BAO/CustomField.php
+++ b/CRM/Core/BAO/CustomField.php
@@ -157,13 +157,13 @@ public static function bulkSave($bulkParams, $defaults = []) {
* Fetch object based on array of properties.
*
* @param array $params
- * (reference ) an assoc array of name/value pairs.
+ * An assoc array of name/value pairs.
* @param array $defaults
* (reference ) an assoc array to hold the flattened values.
*
* @return CRM_Core_DAO_CustomField
*/
- public static function retrieve(&$params, &$defaults) {
+ public static function retrieve($params, &$defaults) {
return CRM_Core_DAO::commonRetrieve('CRM_Core_DAO_CustomField', $params, $defaults);
}
diff --git a/CRM/Core/DAO/CustomField.php b/CRM/Core/DAO/CustomField.php
index 698d34a4956d..5edafdf5c6e1 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:4ded3c0d1a8e34502a5957ee74c4480a)
+ * (GenCodeChecksum:b74179ea5553c544931562d6aac5641e)
*/
/**
@@ -365,6 +365,7 @@ public static function &fields() {
'localizable' => 0,
'html' => [
'type' => 'Select',
+ 'label' => ts("Data Type"),
],
'pseudoconstant' => [
'callback' => 'CRM_Core_BAO_CustomField::dataType',
@@ -384,6 +385,10 @@ public static function &fields() {
'entity' => 'CustomField',
'bao' => 'CRM_Core_BAO_CustomField',
'localizable' => 0,
+ 'html' => [
+ 'type' => 'Select',
+ 'label' => ts("Field Input Type"),
+ ],
'pseudoconstant' => [
'callback' => 'CRM_Core_SelectValues::customHtmlType',
],
diff --git a/CRM/Core/SelectValues.php b/CRM/Core/SelectValues.php
index 7adcd178c528..b81422698ff8 100644
--- a/CRM/Core/SelectValues.php
+++ b/CRM/Core/SelectValues.php
@@ -177,7 +177,6 @@ public static function customHtmlType() {
'RichTextEditor' => ts('Rich Text Editor'),
'Autocomplete-Select' => ts('Autocomplete-Select'),
'Link' => ts('Link'),
- 'ContactReference' => ts('Autocomplete-Select'),
];
}
diff --git a/CRM/Core/xml/Menu/Admin.xml b/CRM/Core/xml/Menu/Admin.xml
index df4d108a1d47..245b7ae549bd 100644
--- a/CRM/Core/xml/Menu/Admin.xml
+++ b/CRM/Core/xml/Menu/Admin.xml
@@ -36,11 +36,6 @@
Custom Field - Move
CRM_Custom_Form_MoveField
- -
-
civicrm/admin/custom/group/field/changetype
- Custom Field - Change Type
- CRM_Custom_Form_ChangeFieldType
-
-
civicrm/admin/uf/group
Profiles
diff --git a/CRM/Custom/Form/ChangeFieldType.php b/CRM/Custom/Form/ChangeFieldType.php
deleted file mode 100644
index 54f9197ea853..000000000000
--- a/CRM/Custom/Form/ChangeFieldType.php
+++ /dev/null
@@ -1,309 +0,0 @@
-_id = CRM_Utils_Request::retrieve('id', 'Positive',
- $this, TRUE
- );
-
- $this->_values = [];
- $params = ['id' => $this->_id];
- CRM_Core_BAO_CustomField::retrieve($params, $this->_values);
-
- if ($this->_values['html_type'] == 'Select' && $this->_values['serialize']) {
- $this->_values['html_type'] = 'Multi-Select';
- }
- $this->_htmlTypeTransitions = self::fieldTypeTransitions(CRM_Utils_Array::value('data_type', $this->_values),
- CRM_Utils_Array::value('html_type', $this->_values)
- );
-
- if (empty($this->_values) || empty($this->_htmlTypeTransitions)) {
- CRM_Core_Error::statusBounce(ts("Invalid custom field or can't change input type of this custom field."));
- }
-
- $url = CRM_Utils_System::url('civicrm/admin/custom/group/field/update',
- "action=update&reset=1&gid={$this->_values['custom_group_id']}&id={$this->_id}"
- );
- $session = CRM_Core_Session::singleton();
- $session->pushUserContext($url);
-
- CRM_Utils_System::setTitle(ts('Change Field Type: %1',
- [1 => $this->_values['label']]
- ));
- }
-
- /**
- * Build the form object.
- *
- * @return void
- */
- public function buildQuickForm() {
-
- $srcHtmlType = $this->add('select',
- 'src_html_type',
- ts('Current HTML Type'),
- [$this->_values['html_type'] => $this->_values['html_type']],
- TRUE
- );
-
- $srcHtmlType->setValue($this->_values['html_type']);
- $srcHtmlType->freeze();
-
- $this->assign('srcHtmlType', $this->_values['html_type']);
-
- $dstHtmlType = $this->add('select',
- 'dst_html_type',
- ts('New HTML Type'),
- [
- '' => ts('- select -'),
- ] + $this->_htmlTypeTransitions,
- TRUE
- );
-
- $this->addButtons([
- [
- 'type' => 'next',
- 'name' => ts('Change Field Type'),
- 'isDefault' => TRUE,
- 'js' => ['onclick' => 'return checkCustomDataField();'],
- ],
- [
- 'type' => 'cancel',
- 'name' => ts('Cancel'),
- ],
- ]);
- }
-
- /**
- * Process the form when submitted.
- *
- * @return void
- */
- public function postProcess() {
- $params = $this->controller->exportValues($this->_name);
-
- $tableName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup',
- $this->_values['custom_group_id'],
- 'table_name'
- );
-
- $singleValueOps = [
- 'Text',
- 'Select',
- 'Radio',
- 'Autocomplete-Select',
- ];
-
- $mutliValueOps = [
- 'CheckBox',
- 'Multi-Select',
- ];
-
- $srcHtmlType = $this->_values['html_type'];
- $dstHtmlType = $params['dst_html_type'];
-
- $customField = new CRM_Core_DAO_CustomField();
- $customField->id = $this->_id;
- $customField->find(TRUE);
- $customField->serialize = in_array($dstHtmlType, $mutliValueOps, TRUE);
-
- if ($dstHtmlType == 'Text' && in_array($srcHtmlType, [
- 'Select',
- 'Radio',
- 'Autocomplete-Select',
- ])) {
- $customField->option_group_id = 'NULL';
- CRM_Core_BAO_CustomField::checkOptionGroup($this->_values['option_group_id']);
- }
-
- if (in_array($srcHtmlType, $mutliValueOps) &&
- in_array($dstHtmlType, $singleValueOps)) {
- $this->flattenToFirstValue($tableName, $this->_values['column_name']);
- }
- elseif (in_array($srcHtmlType, $singleValueOps) &&
- in_array($dstHtmlType, $mutliValueOps)) {
- $this->firstValueToFlatten($tableName, $this->_values['column_name']);
- }
-
- $customField->html_type = ($dstHtmlType === 'Multi-Select') ? 'Select' : $dstHtmlType;
- $customField->save();
-
- // Reset cache for custom fields
- Civi::cache('fields')->flush();
- // reset ACL and system caches.
- CRM_Core_BAO_Cache::resetCaches();
-
- CRM_Core_Session::setStatus(ts('Input type of custom field \'%1\' has been successfully changed to \'%2\'.',
- [1 => $this->_values['label'], 2 => $dstHtmlType]
- ), ts('Field Type Changed'), 'success');
- }
-
- /**
- * @param $dataType
- * @param $htmlType
- *
- * @return array|null
- */
- public static function fieldTypeTransitions($dataType, $htmlType) {
- // Text field is single value field,
- // can not be change to other single value option which contains option group
- if ($htmlType == 'Text') {
- return NULL;
- }
-
- $singleValueOps = [
- 'Text' => 'Text',
- 'Select' => 'Select',
- 'Radio' => 'Radio',
- 'Autocomplete-Select' => 'Autocomplete-Select',
- ];
-
- $mutliValueOps = [
- 'CheckBox' => 'CheckBox',
- 'Multi-Select' => 'Multi-Select',
- ];
-
- switch ($dataType) {
- case 'String':
- if (in_array($htmlType, array_keys($singleValueOps))) {
- unset($singleValueOps[$htmlType]);
- return array_merge($singleValueOps, $mutliValueOps);
- }
- elseif (in_array($htmlType, array_keys($mutliValueOps))) {
- unset($singleValueOps['Text']);
- foreach ($singleValueOps as $type => $label) {
- $singleValueOps[$type] = "{$label} ( " . ts('Not Safe') . " )";
- }
- unset($mutliValueOps[$htmlType]);
- return array_merge($mutliValueOps, $singleValueOps);
- }
- break;
-
- case 'Int':
- case 'Float':
- case 'Money':
- if (in_array($htmlType, array_keys($singleValueOps))) {
- unset($singleValueOps[$htmlType]);
- return $singleValueOps;
- }
- break;
-
- case 'Memo':
- $ops = [
- 'TextArea' => 'TextArea',
- 'RichTextEditor' => 'RichTextEditor',
- ];
- if (in_array($htmlType, array_keys($ops))) {
- unset($ops[$htmlType]);
- return $ops;
- }
- break;
- }
-
- return NULL;
- }
-
- /**
- * Take a single-value column (eg: a Radio or Select etc ) and convert
- * value to the multi listed value (eg:"^Foo^")
- *
- * @param string $table
- * @param string $column
- */
- public function firstValueToFlatten($table, $column) {
- $selectSql = "SELECT id, $column FROM $table WHERE $column IS NOT NULL";
- $updateSql = "UPDATE $table SET $column = %1 WHERE id = %2";
- $dao = CRM_Core_DAO::executeQuery($selectSql);
- while ($dao->fetch()) {
- if (!$dao->{$column}) {
- continue;
- }
- $value = CRM_Core_DAO::VALUE_SEPARATOR . $dao->{$column} . CRM_Core_DAO::VALUE_SEPARATOR;
- $params = [
- 1 => [(string) $value, 'String'],
- 2 => [$dao->id, 'Integer'],
- ];
- CRM_Core_DAO::executeQuery($updateSql, $params);
- }
- }
-
- /**
- * Take a multi-value column (e.g. a Multi-Select or CheckBox column), and convert
- * all values (of the form "^^" or "^Foo^" or "^Foo^Bar^") to the first listed value ("Foo")
- *
- * @param string $table
- * @param string $column
- */
- public function flattenToFirstValue($table, $column) {
- $selectSql = "SELECT id, $column FROM $table WHERE $column IS NOT NULL";
- $updateSql = "UPDATE $table SET $column = %1 WHERE id = %2";
- $dao = CRM_Core_DAO::executeQuery($selectSql);
- while ($dao->fetch()) {
- $values = self::explode($dao->{$column});
- $params = [
- 1 => [(string) array_shift($values), 'String'],
- 2 => [$dao->id, 'Integer'],
- ];
- CRM_Core_DAO::executeQuery($updateSql, $params);
- }
- }
-
- /**
- * @param $str
- *
- * @return array
- */
- public static function explode($str) {
- if (empty($str) || $str == CRM_Core_DAO::VALUE_SEPARATOR . CRM_Core_DAO::VALUE_SEPARATOR) {
- return [];
- }
- else {
- return explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($str, CRM_Core_DAO::VALUE_SEPARATOR));
- }
- }
-
-}
diff --git a/CRM/Custom/Form/Field.php b/CRM/Custom/Form/Field.php
index 2bbc8e0c073d..ba68cc706a72 100644
--- a/CRM/Custom/Form/Field.php
+++ b/CRM/Custom/Form/Field.php
@@ -39,13 +39,6 @@ class CRM_Custom_Form_Field extends CRM_Core_Form {
*/
protected $_id;
- /**
- * The default custom data/input types, when editing the field
- *
- * @var array
- */
- protected $_defaultDataType;
-
/**
* Array of custom field values if update mode.
* @var array
@@ -57,36 +50,26 @@ class CRM_Custom_Form_Field extends CRM_Core_Form {
*
* @var array
*/
- private static $_dataTypeValues = NULL;
- private static $_dataTypeKeys = NULL;
-
- private static $_dataToLabels = NULL;
+ public static $htmlTypesWithOptions = ['Select', 'Radio', 'CheckBox', 'Autocomplete-Select'];
/**
- * Used for mapping data types to html type options.
+ * Maps each data_type to allowed html_type options
*
- * Each item in this array corresponds to the same index in the dataType array
- * @var array
+ * @var array[]
*/
public static $_dataToHTML = [
- [
- 'Text' => 'Text',
- 'Select' => 'Select',
- 'Radio' => 'Radio',
- 'CheckBox' => 'CheckBox',
- 'Autocomplete-Select' => 'Autocomplete-Select',
- ],
- ['Text' => 'Text', 'Select' => 'Select', 'Radio' => 'Radio'],
- ['Text' => 'Text', 'Select' => 'Select', 'Radio' => 'Radio'],
- ['Text' => 'Text', 'Select' => 'Select', 'Radio' => 'Radio'],
- ['TextArea' => 'TextArea', 'RichTextEditor' => 'RichTextEditor'],
- ['Date' => 'Select Date'],
- ['Radio' => 'Radio'],
- ['StateProvince' => 'Select'],
- ['Country' => 'Select'],
- ['File' => 'File'],
- ['Link' => 'Link'],
- ['ContactReference' => 'Autocomplete-Select'],
+ 'String' => ['Text', 'Select', 'Radio', 'CheckBox', 'Autocomplete-Select'],
+ 'Int' => ['Text', 'Select', 'Radio'],
+ 'Float' => ['Text', 'Select', 'Radio'],
+ 'Money' => ['Text', 'Select', 'Radio'],
+ 'Memo' => ['TextArea', 'RichTextEditor'],
+ 'Date' => ['Select Date'],
+ 'Boolean' => ['Radio'],
+ 'StateProvince' => ['Select'],
+ 'Country' => ['Select'],
+ 'File' => ['File'],
+ 'Link' => ['Link'],
+ 'ContactReference' => ['Autocomplete-Select'],
];
/**
@@ -95,19 +78,15 @@ class CRM_Custom_Form_Field extends CRM_Core_Form {
* @return void
*/
public function preProcess() {
- if (!(self::$_dataTypeKeys)) {
- self::$_dataTypeKeys = array_keys(CRM_Core_BAO_CustomField::dataType());
- self::$_dataTypeValues = array_values(CRM_Core_BAO_CustomField::dataType());
- }
-
//custom field id
$this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
+ $this->assign('dataToHTML', self::$_dataToHTML);
+
$this->_values = [];
//get the values form db if update.
if ($this->_id) {
- $params = ['id' => $this->_id];
- CRM_Core_BAO_CustomField::retrieve($params, $this->_values);
+ CRM_Core_BAO_CustomField::retrieve(['id' => $this->_id], $this->_values);
// note_length is an alias for the text_length field
$this->_values['note_length'] = $this->_values['text_length'] ?? NULL;
// custom group id
@@ -130,41 +109,6 @@ public function preProcess() {
$session = CRM_Core_Session::singleton();
$session->pushUserContext($url);
}
-
- if (self::$_dataToLabels == NULL) {
- self::$_dataToLabels = [
- [
- 'Text' => ts('Text'),
- 'Select' => ts('Select'),
- 'Radio' => ts('Radio'),
- 'CheckBox' => ts('CheckBox'),
- 'Autocomplete-Select' => ts('Autocomplete-Select'),
- ],
- [
- 'Text' => ts('Text'),
- 'Select' => ts('Select'),
- 'Radio' => ts('Radio'),
- ],
- [
- 'Text' => ts('Text'),
- 'Select' => ts('Select'),
- 'Radio' => ts('Radio'),
- ],
- [
- 'Text' => ts('Text'),
- 'Select' => ts('Select'),
- 'Radio' => ts('Radio'),
- ],
- ['TextArea' => ts('TextArea'), 'RichTextEditor' => ts('Rich Text Editor')],
- ['Date' => ts('Select Date')],
- ['Radio' => ts('Radio')],
- ['Select' => ts('Select')],
- ['Select' => ts('Select')],
- ['File' => ts('Select File')],
- ['Link' => ts('Link')],
- ['ContactReference' => ts('Autocomplete-Select')],
- ];
- }
}
/**
@@ -177,19 +121,12 @@ public function preProcess() {
public function setDefaultValues() {
$defaults = $this->_values;
+ // Defaults for update mode
if ($this->_id) {
$this->assign('id', $this->_id);
$this->_gid = $defaults['custom_group_id'];
$defaultValue = $defaults['default_value'] ?? NULL;
- //get the value for state or country
- if ($defaults['data_type'] == 'StateProvince' && $defaultValue) {
- $defaults['default_value'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_StateProvince', $defaultValue);
- }
- elseif ($defaults['data_type'] == 'Country' && $defaultValue) {
- $defaults['default_value'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Country', $defaultValue);
- }
-
if ($defaults['data_type'] == 'ContactReference' && !empty($defaults['filter'])) {
$contactRefFilter = 'Advance';
if (strpos($defaults['filter'], 'action=lookup') !== FALSE &&
@@ -215,51 +152,32 @@ public function setDefaultValues() {
$defaults['filter_selected'] = $contactRefFilter;
}
- if (!empty($defaults['data_type'])) {
- $defaultDataType = array_search($defaults['data_type'],
- self::$_dataTypeKeys
- );
- $defaultHTMLType = array_search($defaults['html_type'],
- self::$_dataToHTML[$defaultDataType]
- );
- $defaults['data_type'] = [
- '0' => $defaultDataType,
- '1' => $defaultHTMLType,
- ];
- $this->_defaultDataType = $defaults['data_type'];
- }
-
$defaults['option_type'] = 2;
-
- $this->assign('changeFieldType', CRM_Custom_Form_ChangeFieldType::fieldTypeTransitions($this->_values['data_type'], $this->_values['html_type']));
}
- else {
+
+ // Defaults for create mode
+ if ($this->_action & CRM_Core_Action::ADD) {
+ $defaults['data_type'] = 'String';
+ $defaults['html_type'] = 'Text';
$defaults['is_active'] = 1;
$defaults['option_type'] = 1;
$defaults['is_search_range'] = 1;
- }
-
- // set defaults for weight.
- for ($i = 1; $i <= self::NUM_OPTION; $i++) {
- $defaults['option_status[' . $i . ']'] = 1;
- $defaults['option_weight[' . $i . ']'] = $i;
- $defaults['option_value[' . $i . ']'] = $i;
- }
-
- if ($this->_action & CRM_Core_Action::ADD) {
- $fieldValues = ['custom_group_id' => $this->_gid];
- $defaults['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_CustomField', $fieldValues);
-
+ $defaults['weight'] = CRM_Utils_Weight::getDefaultWeight('CRM_Core_DAO_CustomField', ['custom_group_id' => $this->_gid]);
$defaults['text_length'] = 255;
$defaults['note_columns'] = 60;
$defaults['note_rows'] = 4;
$defaults['is_view'] = 0;
+
+ if (CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_gid, 'is_multiple')) {
+ $defaults['in_selector'] = 1;
+ }
}
- if ($this->_action & CRM_Core_Action::ADD &&
- CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_gid, 'is_multiple', 'id')
- ) {
- $defaults['in_selector'] = 1;
+ // Set defaults for option values.
+ for ($i = 1; $i <= self::NUM_OPTION; $i++) {
+ $defaults['option_status[' . $i . ']'] = 1;
+ $defaults['option_weight[' . $i . ']'] = $i;
+ $defaults['option_value[' . $i . ']'] = $i;
}
return $defaults;
@@ -277,8 +195,6 @@ public function buildQuickForm() {
$this->assign('gid', $this->_gid);
}
- $this->assign('dataTypeKeys', self::$_dataTypeKeys);
-
// lets trim all the whitespace
$this->applyFilter('__ALL__', 'trim');
@@ -292,17 +208,11 @@ public function buildQuickForm() {
TRUE
);
- $dt = &self::$_dataTypeValues;
- $it = [];
- foreach ($dt as $key => $value) {
- $it[$key] = self::$_dataToLabels[$key];
- }
- $sel = &$this->addElement('hierselect',
- 'data_type',
- ts('Data and Input Field Type'),
- ' '
- );
- $sel->setOptions([$dt, $it]);
+ // FIXME: Switch addField to use APIv4 so we don't get those legacy options from v3
+ $htmlOptions = CRM_Core_BAO_CustomField::buildOptions('html_type', 'create');
+
+ $this->addField('data_type', ['class' => 'twenty'], TRUE);
+ $this->addField('html_type', ['class' => 'twenty', 'options' => $htmlOptions], TRUE);
if (CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_gid, 'is_multiple')) {
$this->add('checkbox', 'in_selector', ts('Display in Table?'));
@@ -320,12 +230,17 @@ public function buildQuickForm() {
if ($this->_action == CRM_Core_Action::UPDATE) {
$this->freeze('data_type');
if (!empty($this->_values['option_group_id'])) {
- $this->assign('hasOptionGroup', TRUE);
+ $this->assign('hasOptionGroup', in_array($this->_values['html_type'], self::$htmlTypesWithOptions));
// Before dev/core#155 we didn't set the is_reserved flag properly, which should be handled by the upgrade script...
// but it is still possible that existing installs may have optiongroups linked to custom fields that are marked reserved.
$optionGroupParams['id'] = $this->_values['option_group_id'];
$optionGroupParams['options']['or'] = [["is_reserved", "id"]];
}
+ $this->assign('originalHtmlType', $this->_values['html_type']);
+ $this->assign('originalSerialize', $this->_values['serialize']);
+ if (!empty($this->_values['serialize'])) {
+ $this->assign('existingMultiValueCount', $this->getMultiValueCount());
+ }
}
// Retrieve optiongroups for selection list
@@ -531,8 +446,7 @@ public function buildQuickForm() {
// is searchable by range?
$this->addRadio('is_search_range', ts('Search by Range?'), [ts('No'), ts('Yes')]);
- // add buttons
- $this->addButtons([
+ $buttons = [
[
'type' => 'done',
'name' => ts('Save'),
@@ -547,7 +461,14 @@ public function buildQuickForm() {
'type' => 'cancel',
'name' => ts('Cancel'),
],
- ]);
+ ];
+ // Save & new only applies to adding a field
+ if ($this->_id) {
+ unset($buttons[1]);
+ }
+
+ // add buttons
+ $this->addButtons($buttons);
// add a form rule to check default value
$this->addFormRule(['CRM_Custom_Form_Field', 'formRule'], $this);
@@ -617,11 +538,7 @@ public static function formRule($fields, $files, $self) {
$errors['label'] = ts("You cannot use 'id' as a field label.");
}
- if (!isset($fields['data_type'][0]) || !isset($fields['data_type'][1])) {
- $errors['_qf_default'] = ts('Please enter valid - Data and Input Field Type.');
- }
-
- $dataType = self::$_dataTypeKeys[$fields['data_type'][0]];
+ $dataType = $fields['data_type'];
if ($default || $dataType == 'ContactReference') {
switch ($dataType) {
@@ -663,8 +580,8 @@ public static function formRule($fields, $files, $self) {
case 'Country':
if (!empty($default)) {
- $query = "SELECT count(*) FROM civicrm_country WHERE name = %1 OR iso_code = %1";
- $params = [1 => [$fields['default_value'], 'String']];
+ $query = "SELECT count(*) FROM civicrm_country WHERE id = %1";
+ $params = [1 => [$fields['default_value'], 'Int']];
if (CRM_Core_DAO::singleValueQuery($query, $params) <= 0) {
$errors['default_value'] = ts('Invalid default value for country.');
}
@@ -676,9 +593,8 @@ public static function formRule($fields, $files, $self) {
$query = "
SELECT count(*)
FROM civicrm_state_province
- WHERE name = %1
- OR abbreviation = %1";
- $params = [1 => [$fields['default_value'], 'String']];
+ WHERE id = %1";
+ $params = [1 => [$fields['default_value'], 'Int']];
if (CRM_Core_DAO::singleValueQuery($query, $params) <= 0) {
$errors['default_value'] = ts('The invalid default value for State/Province data type');
}
@@ -699,7 +615,7 @@ public static function formRule($fields, $files, $self) {
}
}
- if (self::$_dataTypeKeys[$fields['data_type'][0]] == 'Date') {
+ if ($dataType == 'Date') {
if (!$fields['date_format']) {
$errors['date_format'] = ts('Please select a date format.');
}
@@ -711,11 +627,7 @@ public static function formRule($fields, $files, $self) {
*/
$_flagOption = $_rowError = 0;
$_showHide = new CRM_Core_ShowHideBlocks('', '');
- $dataType = self::$_dataTypeKeys[$fields['data_type'][0]];
- if (isset($fields['data_type'][1])) {
- $dataField = $fields['data_type'][1];
- }
- $optionFields = ['Select', 'CheckBox', 'Radio'];
+ $htmlType = $fields['html_type'];
if (isset($fields['option_type']) && $fields['option_type'] == 1) {
//capture duplicate Custom option values
@@ -827,8 +739,7 @@ public static function formRule($fields, $files, $self) {
$_flagOption = $_emptyRow = 0;
}
}
- elseif (isset($dataField) &&
- in_array($dataField, $optionFields) &&
+ elseif (in_array($htmlType, self::$htmlTypesWithOptions) &&
!in_array($dataType, ['Boolean', 'Country', 'StateProvince'])
) {
if (!$fields['option_group_id']) {
@@ -841,10 +752,7 @@ public static function formRule($fields, $files, $self) {
WHERE data_type != %1
AND option_group_id = %2";
$params = [
- 1 => [
- self::$_dataTypeKeys[$fields['data_type'][0]],
- 'String',
- ],
+ 1 => [$dataType, 'String'],
2 => [$fields['option_group_id'], 'Integer'],
];
$count = CRM_Core_DAO::singleValueQuery($query, $params);
@@ -860,18 +768,10 @@ public static function formRule($fields, $files, $self) {
$assignError->assign('optionRowError', $_rowError);
}
else {
- if (isset($fields['data_type'][1])) {
- switch (self::$_dataToHTML[$fields['data_type'][0]][$fields['data_type'][1]]) {
+ if (isset($htmlType)) {
+ switch ($htmlType) {
case 'Radio':
- $_fieldError = 1;
- $assignError->assign('fieldError', $_fieldError);
- break;
-
- case 'Checkbox':
- $_fieldError = 1;
- $assignError->assign('fieldError', $_fieldError);
- break;
-
+ case 'CheckBox':
case 'Select':
$_fieldError = 1;
$assignError->assign('fieldError', $_fieldError);
@@ -900,6 +800,27 @@ public static function formRule($fields, $files, $self) {
$errors['is_view'] = ts('Can not set this field Required and View Only at the same time.');
}
+ // If switching to a new option list, validate existing data
+ if (empty($errors) && $self->_id && in_array($htmlType, self::$htmlTypesWithOptions)) {
+ $oldHtmlType = $self->_values['html_type'];
+ $oldOptionGroup = $self->_values['option_group_id'];
+ if ($oldHtmlType === 'Text' || $oldOptionGroup != $fields['option_group_id'] || $fields['option_type'] == 1) {
+ if ($fields['option_type'] == 2) {
+ $optionQuery = "SELECT value FROM civicrm_option_value WHERE option_group_id = " . (int) $fields['option_group_id'];
+ }
+ else {
+ $options = array_map(['CRM_Core_DAO', 'escapeString'], array_filter($fields['option_value'], 'strlen'));
+ $optionQuery = '"' . implode('","', $options) . '"';
+ }
+ $table = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $self->_gid, 'table_name');
+ $column = $self->_values['column_name'];
+ $invalid = CRM_Core_DAO::singleValueQuery("SELECT COUNT(*) FROM `$table` WHERE `$column` NOT IN ($optionQuery)");
+ if ($invalid) {
+ $errors['html_type'] = ts('Cannot impose option list because there is existing data which does not match the options.');
+ }
+ }
+ }
+
return empty($errors) ? TRUE : $errors;
}
@@ -912,24 +833,9 @@ public function postProcess() {
// store the submitted values in an array
$params = $this->controller->exportValues($this->_name);
self::clearEmptyOptions($params);
- if ($this->_action == CRM_Core_Action::UPDATE) {
- $dataTypeKey = $this->_defaultDataType[0];
- $params['data_type'] = self::$_dataTypeKeys[$this->_defaultDataType[0]];
- $params['html_type'] = self::$_dataToHTML[$this->_defaultDataType[0]][$this->_defaultDataType[1]];
- }
- else {
- $dataTypeKey = $params['data_type'][0];
- $params['html_type'] = self::$_dataToHTML[$params['data_type'][0]][$params['data_type'][1]];
- $params['data_type'] = self::$_dataTypeKeys[$params['data_type'][0]];
- }
//fix for 'is_search_range' field.
- if (in_array($dataTypeKey, [
- 1,
- 2,
- 3,
- 5,
- ])) {
+ if (in_array($params['data_type'], ['Int', 'Float', 'Money', 'Date'])) {
if (empty($params['is_searchable'])) {
$params['is_search_range'] = 0;
}
@@ -938,11 +844,7 @@ public function postProcess() {
$params['is_search_range'] = 0;
}
- // Serialization cannot be changed on update
- if ($this->_id) {
- unset($params['serialize']);
- }
- elseif (strpos($params['html_type'], 'Select') === 0) {
+ if ($params['html_type'] === 'Select') {
$params['serialize'] = $params['serialize'] ? CRM_Core_DAO::SERIALIZE_SEPARATOR_BOOKEND : 'null';
}
else {
@@ -950,12 +852,11 @@ public function postProcess() {
}
$filter = 'null';
- if ($dataTypeKey == 11 && !empty($params['filter_selected'])) {
+ if ($params['data_type'] == 'ContactReference' && !empty($params['filter_selected'])) {
if ($params['filter_selected'] == 'Advance' && trim(CRM_Utils_Array::value('filter', $params))) {
$filter = trim($params['filter']);
}
elseif ($params['filter_selected'] == 'Group' && !empty($params['group_id'])) {
-
$filter = 'action=lookup&group=' . implode(',', $params['group_id']);
}
}
@@ -971,43 +872,6 @@ public function postProcess() {
$params['weight'] = CRM_Utils_Weight::updateOtherWeights('CRM_Core_DAO_CustomField', $oldWeight, $params['weight'], $fieldValues);
}
- $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower';
-
- //store the primary key for State/Province or Country as default value.
- if (strlen(trim($params['default_value']))) {
- switch ($params['data_type']) {
- case 'StateProvince':
- $fieldStateProvince = $strtolower($params['default_value']);
-
- // LOWER in query below roughly translates to 'hurt my database without deriving any benefit' See CRM-19811.
- $query = "
-SELECT id
- FROM civicrm_state_province
- WHERE LOWER(name) = '$fieldStateProvince'
- OR abbreviation = '$fieldStateProvince'";
- $dao = CRM_Core_DAO::executeQuery($query);
- if ($dao->fetch()) {
- $params['default_value'] = $dao->id;
- }
- break;
-
- case 'Country':
- $fieldCountry = $strtolower($params['default_value']);
-
- // LOWER in query below roughly translates to 'hurt my database without deriving any benefit' See CRM-19811.
- $query = "
-SELECT id
- FROM civicrm_country
- WHERE LOWER(name) = '$fieldCountry'
- OR iso_code = '$fieldCountry'";
- $dao = CRM_Core_DAO::executeQuery($query);
- if ($dao->fetch()) {
- $params['default_value'] = $dao->id;
- }
- break;
- }
- }
-
// The text_length attribute for Memo fields is in a different input as there
// are different label, help text and default value than for other type fields
if ($params['data_type'] == "Memo") {
@@ -1062,4 +926,32 @@ public static function clearEmptyOptions(&$fields) {
}
}
+ /**
+ * Get number of existing records for this field that contain more than one serialized value.
+ *
+ * @return int
+ * @throws CRM_Core_Exception
+ */
+ public function getMultiValueCount() {
+ $table = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $this->_gid, 'table_name');
+ $column = $this->_values['column_name'];
+ $sp = CRM_Core_DAO::VALUE_SEPARATOR;
+ $sql = "SELECT COUNT(*) FROM `$table` WHERE `$column` LIKE '{$sp}%{$sp}%{$sp}'";
+ return (int) CRM_Core_DAO::singleValueQuery($sql);
+ }
+
+ /**
+ * @return string
+ */
+ public function getDefaultContext() {
+ return 'create';
+ }
+
+ /**
+ * @return string
+ */
+ public function getDefaultEntity() {
+ return 'CustomField';
+ }
+
}
diff --git a/js/Common.js b/js/Common.js
index f42314f6edb8..881dda124d0a 100644
--- a/js/Common.js
+++ b/js/Common.js
@@ -289,6 +289,17 @@ if (!CRM.vars) CRM.vars = {};
return rendered;
};
+ CRM.utils.getOptions = function(select) {
+ var options = [];
+ $('option', select).each(function() {
+ var option = {key: $(this).attr('value'), value: $(this).text()};
+ if (option.key !== '') {
+ options.push(option);
+ }
+ });
+ return options;
+ };
+
function chainSelect() {
var $form = $(this).closest('form'),
$target = $('select[data-name="' + $(this).data('target') + '"]', $form),
diff --git a/templates/CRM/Custom/Form/ChangeFieldType.tpl b/templates/CRM/Custom/Form/ChangeFieldType.tpl
deleted file mode 100644
index e87067ea8447..000000000000
--- a/templates/CRM/Custom/Form/ChangeFieldType.tpl
+++ /dev/null
@@ -1,46 +0,0 @@
-{*
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC. All rights reserved. |
- | |
- | This work is published under the GNU AGPLv3 license with some |
- | permitted exceptions and without any warranty. For full license |
- | and copyright information, see https://civicrm.org/licensing |
- +--------------------------------------------------------------------+
-*}
-
-{literal}
-
-{/literal}
-
diff --git a/templates/CRM/Custom/Form/Field.tpl b/templates/CRM/Custom/Form/Field.tpl
index 5dd62613b9ca..aeb56d695bc6 100644
--- a/templates/CRM/Custom/Form/Field.tpl
+++ b/templates/CRM/Custom/Form/Field.tpl
@@ -20,29 +20,16 @@
{$form.data_type.label}
- {$form.data_type.html}
- {if $action neq 1 && $form.data_type.value[1][0] eq "Select" && $form.serialize.value}
- ({ts}Multi-Select{/ts})
- {/if}
- {if $action neq 4 and $action neq 2}
- {ts}Select the type of data you want to collect and store for this contact. Then select from the available HTML input field types (choices are based on the type of data being collected).{/ts}
- {/if}
- {if $action eq 2 and $changeFieldType}
-
-
-
- {ts}Change Input Field Type{/ts}
-
-
- {/if}
-
+ {$form.data_type.html}
+
+
+ {$form.html_type.label}
+ {$form.html_type.html}
+
+
+ {$form.serialize.label}
+ {$form.serialize.html}
- {if $action eq 1}
-
- {$form.serialize.label}
- {$form.serialize.html}
-
- {/if}
{if $form.in_selector}
{$form.in_selector.label}
@@ -176,19 +163,45 @@
{literal}
{/literal}
diff --git a/tests/phpunit/api/v3/CustomFieldTest.php b/tests/phpunit/api/v3/CustomFieldTest.php
index e5c900dd245f..cfa7894fe48d 100644
--- a/tests/phpunit/api/v3/CustomFieldTest.php
+++ b/tests/phpunit/api/v3/CustomFieldTest.php
@@ -108,22 +108,13 @@ public function testCustomFieldCreateAllAvailableFormInputs() {
$htype = CRM_Custom_Form_Field::$_dataToHTML;
// Legacy html types returned by v3
- foreach ($htype as &$item) {
- if (isset($item['StateProvince'])) {
- $item['StateProvince'] = 'Select State/Province';
- }
- if (isset($item['Country'])) {
- $item['Country'] = 'Select Country';
- }
- }
+ $htype['StateProvince'] = ['Select State/Province'];
+ $htype['Country'] = ['Select Country'];
- $n = 0;
foreach ($dtype as $dkey => $dvalue) {
- foreach ($htype[$n] as $hkey => $hvalue) {
- //echo $dkey."][".$hvalue."\n";
+ foreach ($htype[$dkey] as $hvalue) {
$this->_loopingCustomFieldCreateTest($this->_buildParams($gid['id'], $hvalue, $dkey));
}
- $n++;
}
}
diff --git a/tests/phpunit/api/v3/CustomValueTest.php b/tests/phpunit/api/v3/CustomValueTest.php
index 02c16401c41c..96ce2e42c0c6 100644
--- a/tests/phpunit/api/v3/CustomValueTest.php
+++ b/tests/phpunit/api/v3/CustomValueTest.php
@@ -95,11 +95,11 @@ public function testCreateCustomValue() {
$customFieldDataType = CRM_Core_BAO_CustomField::dataType();
$dataToHtmlTypes = CRM_Custom_Form_Field::$_dataToHTML;
- $count = 0;
- $optionSupportingHTMLTypes = ['Select', 'Radio', 'CheckBox', 'Autocomplete-Select', 'Multi-Select'];
+ $optionSupportingHTMLTypes = CRM_Custom_Form_Field::$htmlTypesWithOptions;
foreach ($customFieldDataType as $dataType => $label) {
switch ($dataType) {
+ // skipping File data-type & state province due to caching issues
// case 'Country':
// case 'StateProvince':
case 'String':
@@ -139,7 +139,7 @@ public function testCreateCustomValue() {
}
//Create custom field of $dataType and html-type $html
- foreach ($dataToHtmlTypes[$count] as $html) {
+ foreach ($dataToHtmlTypes[$dataType] as $html) {
// per CRM-18568 the like operator does not currently work for fields with options.
// the LIKE operator could potentially bypass ACLs (as could IS NOT NULL) and some thought needs to be given
// to it.
@@ -160,13 +160,7 @@ public function testCreateCustomValue() {
//Now test with $validSQLOperator SQL operators against its custom value(s)
$this->_testCustomValue($customField['values'][$customField['id']], $validSQLOperators, $type);
}
- $count++;
- break;
- default:
- // skipping File data-type & state province due to caching issues
- $count++;
- break;
}
}
}
diff --git a/xml/schema/Core/CustomField.xml b/xml/schema/Core/CustomField.xml
index 44c632256010..54cd5c5d7454 100644
--- a/xml/schema/Core/CustomField.xml
+++ b/xml/schema/Core/CustomField.xml
@@ -73,6 +73,7 @@
1.1
Select
+ Data Type
@@ -85,6 +86,10 @@
CRM_Core_SelectValues::customHtmlType
+
+ Select
+ Field Input Type
+
1.1