* 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);
}
*
* Generated from xml/schema/CRM/Core/CustomField.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:4ded3c0d1a8e34502a5957ee74c4480a)
+ * (GenCodeChecksum:b74179ea5553c544931562d6aac5641e)
*/
/**
'localizable' => 0,
'html' => [
'type' => 'Select',
+ 'label' => ts("Data Type"),
],
'pseudoconstant' => [
'callback' => 'CRM_Core_BAO_CustomField::dataType',
'entity' => 'CustomField',
'bao' => 'CRM_Core_BAO_CustomField',
'localizable' => 0,
+ 'html' => [
+ 'type' => 'Select',
+ 'label' => ts("Field Input Type"),
+ ],
'pseudoconstant' => [
'callback' => 'CRM_Core_SelectValues::customHtmlType',
],
'RichTextEditor' => ts('Rich Text Editor'),
'Autocomplete-Select' => ts('Autocomplete-Select'),
'Link' => ts('Link'),
- 'ContactReference' => ts('Autocomplete-Select'),
];
}
<title>Custom Field - Move</title>
<page_callback>CRM_Custom_Form_MoveField</page_callback>
</item>
- <item>
- <path>civicrm/admin/custom/group/field/changetype</path>
- <title>Custom Field - Change Type</title>
- <page_callback>CRM_Custom_Form_ChangeFieldType</page_callback>
- </item>
<item>
<path>civicrm/admin/uf/group</path>
<title>Profiles</title>
+++ /dev/null
-<?php
-/*
- +--------------------------------------------------------------------+
- | 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 |
- +--------------------------------------------------------------------+
- */
-
-/**
- *
- * @package CRM
- * @copyright CiviCRM LLC https://civicrm.org/licensing
- */
-
-/**
- * This class is to build the form for Deleting Group
- */
-class CRM_Custom_Form_ChangeFieldType extends CRM_Core_Form {
-
- /**
- * The field id
- *
- * @var int
- */
- protected $_id;
-
- /**
- * Array of custom field values
- * @var array
- */
- protected $_values;
-
- /**
- * Mapper array of valid field type
- * @var array
- */
- protected $_htmlTypeTransitions;
-
- /**
- * Set up variables to build the form.
- *
- * @return void
- * @access protected
- */
- public function preProcess() {
- $this->_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));
- }
- }
-
-}
*/
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
*
* @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'],
];
/**
* @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
$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')],
- ];
- }
}
/**
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 &&
$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;
$this->assign('gid', $this->_gid);
}
- $this->assign('dataTypeKeys', self::$_dataTypeKeys);
-
// lets trim all the whitespace
$this->applyFilter('__ALL__', 'trim');
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?'));
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
// 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'),
'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);
$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) {
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.');
}
$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');
}
}
}
- if (self::$_dataTypeKeys[$fields['data_type'][0]] == 'Date') {
+ if ($dataType == 'Date') {
if (!$fields['date_format']) {
$errors['date_format'] = ts('Please select a date format.');
}
*/
$_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
$_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']) {
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);
$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);
$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;
}
// 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;
}
$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 {
}
$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']);
}
}
$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") {
}
}
+ /**
+ * 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';
+ }
+
}
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),
+++ /dev/null
-{*
- +--------------------------------------------------------------------+
- | 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 |
- +--------------------------------------------------------------------+
-*}
-<div class="crm-block crm-form-block crm-custom-field-form-block">
-<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
- <div class='status'>{icon icon="fa-info-circle"}{/icon}
- {ts}Warning: This functionality is currently in beta stage. Consider backing up your database before using it. Click "Cancel" to return to the "edit custom field" form without making changes.{/ts}
- </div>
- <table class="form-layout">
- <tr class="crm-custom-src-field-form-block-label">
- <td class="label">{$form.src_html_type.label}</td>
- <td class="html-adjust">{$form.src_html_type.html}</td>
- </tr>
- <tr class="crm-custom-dst-field-form-block-label">
- <td class="label">{$form.dst_html_type.label}</td>
- <td class="html-adjust">{$form.dst_html_type.html}</td>
- </tr>
- </table>
-<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
-</div>
-{literal}
-<script type="text/Javascript">
- function checkCustomDataField( ) {
- var srcHtmlType = {/literal}{$srcHtmlType|@json_encode}{literal};
- var singleValOps = ['Text', 'Select', 'Radio', 'Autocomplete-Select'];
- var multiValOps = ['CheckBox', 'Multi-Select'];
- var dstHtmlType = cj('#dst_html_type').val( );
- if ( !dstHtmlType ) {
- return true;
- }
-
- if ( ( cj.inArray(srcHtmlType, multiValOps) > -1 ) &&
- ( cj.inArray(dstHtmlType, singleValOps) > -1 ) ) {
- return confirm( "{/literal}{ts escape='js'}Changing a 'multi option' html type to a 'single option' html type, might results in a data loss. Please consider to take db backup before change the html type. Click 'Ok' to continue.{/ts}{literal}" );
- }
- return true;
- }
-</script>
-{/literal}
-
</tr>
<tr class="crm-custom-field-form-block-data_type">
<td class="label">{$form.data_type.label}</td>
- <td class="html-adjust">{$form.data_type.html}
- {if $action neq 1 && $form.data_type.value[1][0] eq "Select" && $form.serialize.value}
- <span>({ts}Multi-Select{/ts})</span>
- {/if}
- {if $action neq 4 and $action neq 2}
- <br /><span class="description">{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}</span>
- {/if}
- {if $action eq 2 and $changeFieldType}
- <br />
- <a class="action-item crm-hover-button" href='{crmURL p="civicrm/admin/custom/group/field/changetype" q="reset=1&id=`$id`"}'>
- <i class="crm-i fa-wrench" aria-hidden="true"></i>
- {ts}Change Input Field Type{/ts}
- </a>
- <div class='clear'></div>
- {/if}
- </td>
+ <td class="html-adjust">{$form.data_type.html}</td>
+ </tr>
+ <tr class="crm-custom-field-form-block-html_type">
+ <td class="label">{$form.html_type.label}</td>
+ <td class="html-adjust">{$form.html_type.html}</td>
+ </tr>
+ <tr class="crm-custom-field-form-block-serialize">
+ <td class="label">{$form.serialize.label}</td>
+ <td class="html-adjust">{$form.serialize.html}</td>
</tr>
- {if $action eq 1}
- <tr class="crm-custom-field-form-block-serialize">
- <td class="label">{$form.serialize.label}</td>
- <td class="html-adjust">{$form.serialize.html}</td>
- </tr>
- {/if}
{if $form.in_selector}
<tr class='crm-custom-field-form-block-in_selector'>
<td class='label'>{$form.in_selector.label}</td>
{literal}
<script type="text/javascript">
CRM.$(function($) {
- var $form = $('form.{/literal}{$form.formClass}{literal}'),
- dataTypes = {/literal}{$dataTypeKeys|@json_encode}{literal};
+ var _ = CRM._,
+ $form = $('form.{/literal}{$form.formClass}{literal}'),
+ dataToHTML = {/literal}{$dataToHTML|@json_encode}{literal},
+ originalHtmlType = '{/literal}{$originalHtmlType}{literal}',
+ existingMultiValueCount = {/literal}{if empty($existingMultiValueCount)}null{else}{$existingMultiValueCount}{/if}{literal},
+ originalSerialize = {/literal}{if empty($originalSerialize)}false{else}true{/if}{literal},
+ htmlTypes = CRM.utils.getOptions($('#html_type', $form));
- function showSearchRange() {
- var htmlType = $("[name='data_type[1]']", $form).val(),
- dataType = dataTypes[$("[name='data_type[0]']", $form).val()];
+ function onChangeDataType() {
+ var dataType = $(this).val(),
+ allowedHtmlTypes = _.filter(htmlTypes, function(type) {
+ return _.includes(dataToHTML[dataType], type.key);
+ });
+ CRM.utils.setOptions($('#html_type', $form), allowedHtmlTypes);
+ if (!$('#html_type', $form).val()) {
+ $('#html_type', $form).val(dataToHTML[dataType][0]).change();
+ }
+ customOptionHtmlType(dataType);
+ makeDefaultValueField(dataType);
+ }
- if (dataType === 'Int' || dataType === 'Float' || dataType === 'Money' || dataType === 'Date') {
- if ($('#is_searchable', $form).is(':checked')) {
- $("#searchByRange", $form).show();
- } else {
- $("#searchByRange", $form).hide();
- }
+ function onChangeHtmlType() {
+ var htmlType = $(this).val(),
+ dataType = $('#data_type', $form).val();
+
+ if (htmlType === 'CheckBox' || htmlType === 'Radio') {
+ $('#serialize', $form).prop('checked', htmlType === 'CheckBox');
+ }
+
+ showSearchRange(dataType);
+ customOptionHtmlType(dataType);
+ }
+
+ $('#data_type', $form).each(onChangeDataType).change(onChangeDataType);
+ $('#html_type', $form).each(onChangeHtmlType).change(onChangeHtmlType);
+
+ function showSearchRange(dataType) {
+ if (_.includes(['Date', 'Int', 'Float', 'Money'], dataType)) {
+ $("#searchByRange", $form).toggle($('#is_searchable', $form).is(':checked'));
} else {
$("#searchByRange", $form).hide();
}
}
$('.toggle-contact-ref-mode', $form).click(toggleContactRefFilter);
- function customOptionHtmlType() {
- var htmlType = $("[name='data_type[1]']", $form).val(),
- dataTypeId = $("[name='data_type[0]']", $form).val(),
- dataType = dataTypes[dataTypeId],
- radioOption, checkBoxOption;
+ function customOptionHtmlType(dataType) {
+ var htmlType = $("#html_type", $form).val(),
+ serialize = $("#serialize", $form).is(':checked');
- if (!htmlType && !dataTypeId) {
+ if (!htmlType) {
return;
}
$('#field_advance_filter, #contact_reference_group', $form).hide();
}
- if (dataTypeId < 4) {
+ if (_.includes(['String', 'Int', 'Float', 'Money'], dataType)) {
if (htmlType !== "Text") {
$("#showoption, #searchable", $form).show();
$("#hideDefault, #hideDesc, #searchByRange", $form).hide();
$("#showoption").hide();
}
- for (var i=1; i<=11; i++) {
- radioOption = 'radio'+i;
- checkBoxOption = 'checkbox'+i;
- if (dataTypeId < 4) {
- if (htmlType != "Text") {
- if (htmlType == "CheckBox" || htmlType == "Multi-Select") {
- $("#"+checkBoxOption, $form).show();
- $("#"+radioOption, $form).hide();
- } else {
- $("#"+radioOption, $form).show();
- $("#"+checkBoxOption, $form).hide();
- }
- }
+ if (_.includes(['String', 'Int', 'Float', 'Money'], dataType) && htmlType !== 'Text') {
+ if (serialize) {
+ $('div[id^=checkbox]', '#optionField').show();
+ $('div[id^=radio]', '#optionField').hide();
+ } else {
+ $('div[id^=radio]', '#optionField').show();
+ $('div[id^=checkbox]', '#optionField').hide();
}
}
- $("#optionsPerLine", $form).toggle((htmlType == "CheckBox" || htmlType == "Radio") && dataType !== 'Boolean');
+ $("#optionsPerLine", $form).toggle((htmlType === "CheckBox" || htmlType === "Radio") && dataType !== 'Boolean');
$("#startDateRange, #endDateRange, #includedDatePart", $form).toggle(dataType === 'Date');
$(".crm-custom-field-form-block-serialize", $form).toggle(htmlType === 'Select');
}
- $('[name^="data_type"]', $form).change(customOptionHtmlType);
- customOptionHtmlType();
- $('#is_searchable, [name^="data_type"]', $form).change(showSearchRange);
- showSearchRange();
+ function makeDefaultValueField(dataType) {
+ var field = $('#default_value', $form);
+ field.crmDatepicker('destroy');
+ field.crmSelect2('destroy');
+ switch (dataType) {
+ case 'Date':
+ field.crmDatepicker({date: 'yy-mm-dd', time: false});
+ break;
+
+ case 'Boolean':
+ field.crmSelect2({data: [{id: '1', text: ts('Yes')}, {id: '0', text: ts('No')}], placeholder: ' '});
+ break;
+
+ case 'Country':
+ field.crmEntityRef({entity: 'Country'});
+ break;
+
+ case 'StateProvince':
+ field.crmEntityRef({entity: 'StateProvince', api: {description_field: ['country_id.name']}});
+ break;
+ }
+ }
+
+ $('#is_searchable, #serialize', $form).change(onChangeHtmlType);
+
+ $form.submit(function() {
+ var htmlType = $('#html_type', $form).val(),
+ serialize = $("#serialize", $form).is(':checked'),
+ htmlTypeLabel = (serialize && htmlType === 'Select') ? ts('Multi-Select') : _.find(htmlTypes, {key: htmlType}).value;
+ if (originalHtmlType && (originalHtmlType !== htmlType || originalSerialize !== serialize)) {
+ var origHtmlTypeLabel = (originalSerialize && originalHtmlType === 'Select') ? ts('Multi-Select') : _.find(htmlTypes, {key: originalHtmlType}).value;
+ if (originalSerialize && !serialize && existingMultiValueCount) {
+ return confirm(ts('WARNING: Changing this multivalued field to singular will result in the loss of data!')
+ + "\n" + ts('%1 existing records contain multiple values - the data in each of these fields will be truncated to a single value.', {1: existingMultiValueCount})
+ )
+ } else {
+ return confirm(ts('Change this field from %1 to %2? Existing data will be preserved.', {1: origHtmlTypeLabel, 2: htmlTypeLabel}));
+ }
+ }
+ });
});
</script>
{/literal}
$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++;
}
}
$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':
}
//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.
//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;
}
}
}
<add>1.1</add>
<html>
<type>Select</type>
+ <label>Data Type</label>
</html>
</field>
<field>
<pseudoconstant>
<callback>CRM_Core_SelectValues::customHtmlType</callback>
</pseudoconstant>
+ <html>
+ <type>Select</type>
+ <label>Field Input Type</label>
+ </html>
<add>1.1</add>
</field>
<field>