*/
use Civi\Api4\CustomField;
+use Civi\Api4\Utils\CoreUtil;
/**
* Business objects for managing custom data fields.
'name' => 'Contact Reference',
'label' => ts('Contact Reference'),
],
+ [
+ 'id' => 'EntityReference',
+ 'name' => 'Entity Reference',
+ 'label' => ts('Entity Reference'),
+ ],
];
}
'File' => CRM_Utils_Type::T_STRING,
'Link' => CRM_Utils_Type::T_STRING,
'ContactReference' => CRM_Utils_Type::T_INT,
+ 'EntityReference' => CRM_Utils_Type::T_INT,
'Country' => CRM_Utils_Type::T_INT,
];
}
if (!$field->find(TRUE)) {
throw new CRM_Core_Exception('Cannot find Custom Field ' . $fieldID);
}
-
$fieldValues = [];
CRM_Core_DAO::storeValues($field, $fieldValues);
);
}
+ if ($field->data_type == 'EntityReference') {
+ $fieldAttributes['entity'] = $field->fk_entity;
+ $element = $qf->addAutocomplete($elementName, $label, $fieldAttributes, $useRequired && !$search);
+ }
else {
// FIXME: This won't work with customFieldOptions hook
$fieldAttributes += [
}
// Do this before the "Select" string search because date fields have a "Select Date" html_type
// and contactRef fields have an "Autocomplete-Select" html_type - contacts are an FK not an option list.
- if (in_array($field['data_type'], ['ContactReference', 'Date'])) {
+ if (in_array($field['data_type'], ['EntityReference', 'ContactReference', 'Date'])) {
return FALSE;
}
if (strpos($field['html_type'], 'Select') !== FALSE) {
'StateProvince' => 'civicrm_state_province',
'ContactReference' => 'civicrm_contact',
'File' => 'civicrm_file',
+ 'EntityReference' => CoreUtil::getInfoItem((string) $field->fk_entity, 'table_name'),
];
if (isset($fkFields[$field->data_type])) {
// Serialized fields store value-separated strings which are incompatible with FK constraints
}
break;
+ case 'EntityReference':
+ $type = 'Integer';
+ break;
+
case 'RichTextEditor':
$type = 'String';
break;
// the below three are FK's, and have constraints added to them
case 'ContactReference':
+ case 'EntityReference':
case 'StateProvince':
case 'Country':
case 'File':
unset($extra['option_context']);
}
+ // Allow disabled to be a boolean
+ if (isset($attributes['disabled']) && $attributes['disabled'] === FALSE) {
+ unset($attributes['disabled']);
+ }
+
$element = $this->addElement($type, $name, CRM_Utils_String::purifyHTML($label), $attributes, $extra);
if (HTML_QuickForm::isError($element)) {
CRM_Core_Error::statusBounce(HTML_QuickForm::errorMessage($element));
}
}
+ /**
+ * @param string $name
+ * @param string $label
+ * @param array $props
+ * @param bool $required
+ *
+ * @return HTML_QuickForm_Element
+ */
+ public function addAutocomplete(string $name, string $label = '', array $props = [], bool $required = FALSE) {
+ $props += [
+ 'entity' => 'Contact',
+ 'api' => [],
+ 'select' => [],
+ ];
+ $props['api'] += [
+ 'formName' => 'qf:' . get_class($this),
+ 'fieldName' => $name,
+ ];
+ $props['class'] = ltrim(($props['class'] ?? '') . ' crm-form-autocomplete');
+ $props['placeholder'] = $props['placeholder'] ?? self::selectOrAnyPlaceholder($props, $required);
+ $props['data-select-params'] = json_encode($props['select']);
+ $props['data-api-params'] = json_encode($props['api']);
+ $props['data-api-entity'] = $props['entity'];
+ CRM_Utils_Array::remove($props, 'select', 'api', 'entity');
+ return $this->add('text', $name, $label, $props, $required);
+ }
+
/**
* Create a single or multiple entity ref field.
* @param string $name
$this->add('checkbox', 'serialize', ts('Multi-Select'));
+ $this->addAutocomplete('fk_entity', ts('Entity'), [
+ 'class' => 'twenty',
+ // Don't allow entity to be changed once field is created
+ 'disabled' => $this->_action == CRM_Core_Action::UPDATE && !empty($this->_values['fk_entity']),
+ 'entity' => 'Entity',
+ 'select' => ['minimumInputLength' => 0],
+ ]);
+
if ($this->_action == CRM_Core_Action::UPDATE) {
$this->freeze('data_type');
if (!empty($this->_values['option_group_id'])) {
}
}
+ if ($dataType === 'EntityReference') {
+ if (empty($fields['fk_entity'])) {
+ $errors['fk_entity'] = ts('Selecting an entity is required');
+ }
+ }
+
if ($dataType == 'Date') {
if (!$fields['date_format']) {
$errors['date_format'] = ts('Please select a date format.');
$dataType = 'Integer';
break;
+ case 'EntityReference':
+ $dataType = 'Integer';
+ break;
+
case 'File':
case 'StateProvince':
case 'Country':
$field->setType('Field');
$field->setTableName($data['custom_group_id.table_name']);
}
+ if ($dataTypeName === 'EntityReference') {
+ $field->setFkEntity($data['fk_entity']);
+ }
$field->setColumnName($data['column_name']);
$field->setNullable(empty($data['is_required']));
$field->setCustomFieldId($data['id'] ?? NULL);
'Link' => 'Url',
];
$inputType = $map[$inputType] ?? $inputType;
- if ($dataTypeName === 'ContactReference') {
+ if ($dataTypeName === 'ContactReference' || $dataTypeName === 'EntityReference') {
$inputType = 'EntityRef';
}
if (in_array($inputType, ['Select', 'EntityRef'], TRUE) && !empty($data['serialize'])) {
}
if (!in_array($dataType, $this->getValidDataTypes())) {
- throw new \CRM_Core_Exception(sprintf('Invalid data type "%s', $dataType));
+ throw new \CRM_Core_Exception(sprintf('Invalid data type "%s"', $dataType));
}
$this->dataType = $dataType;
width: 15em;
}
.crm-container .huge,
+input.crm-form-autocomplete,
input.crm-form-entityref {
width: 25em;
}
}
$('.crm-select2:not(.select2-offscreen, .select2-container)', e.target).crmSelect2();
$('.crm-form-entityref:not(.select2-offscreen, .select2-container)', e.target).crmEntityRef();
+ $('.crm-form-autocomplete:not(.select2-offscreen, .select2-container)[data-api-entity]', e.target).each(function() {
+ $(this).crmAutocomplete($(this).data('apiEntity'), $(this).data('apiParams'), $(this).data('selectParams'));
+ });
$('select.crm-chain-select-control', e.target).off('.chainSelect').on('change.chainSelect', chainSelect);
$('.crm-form-text[data-crm-datepicker]', e.target).each(function() {
$(this).crmDatepicker($(this).data('crmDatepicker'));
<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-fk_entity">
+ <td class="label">{$form.fk_entity.label} <span class="crm-marker">*</span></td>
+ <td class="html-adjust">{$form.fk_entity.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>
if (!$('#html_type', $form).val()) {
$('#html_type', $form).val(dataToHTML[dataType][0]).change();
}
+ // Hide html_type if there is only one option
+ $('.crm-custom-field-form-block-html_type').toggle(allowedHtmlTypes.length > 1);
customOptionHtmlType(dataType);
makeDefaultValueField(dataType);
+
+ // Show/hide entityReference selector
+ $('.crm-custom-field-form-block-fk_entity').toggle(dataType === 'EntityReference');
}
function onChangeHtmlType() {
$("#noteColumns, #noteRows, #noteLength", $form).toggle(dataType === 'Memo');
- $(".crm-custom-field-form-block-serialize", $form).toggle(htmlType === 'Select' || htmlType === 'Autocomplete-Select');
+ $(".crm-custom-field-form-block-serialize", $form).toggle(htmlType === 'Select' || htmlType === 'Autocomplete-Select' && dataType !== 'EntityReference');
}
function makeDefaultValueField(dataType) {