Skip to content

Commit

Permalink
SearchKit - Fix display of contact reference fields (single-value)
Browse files Browse the repository at this point in the history
This fixes the display of contact reference fields, giving feature parity
with other FK fields. Both ID and Display Name are shown as available columns.

This does not address the more difficult question of how to join
multi-valued contact reference fields with contact display names.
  • Loading branch information
colemanw committed Apr 21, 2021
1 parent 5a74121 commit 1cbd793
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 23 deletions.
8 changes: 7 additions & 1 deletion Civi/Api4/Service/Schema/SchemaMapBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ private function addJoins(Table $table, $field, array $data) {
if ($fkClass) {
$tableName = AllCoreTables::getTableForClass($fkClass);
$fkKey = $data['FKKeyColumn'] ?? 'id';
// Fixme: Clumsy string manipulation to transform e.g. "contact_id" to "contact" - we never should have done this
$alias = str_replace('_id', '', $field);
$joinable = new Joinable($tableName, $fkKey, $alias);
$joinable->setJoinType($joinable::JOIN_TYPE_MANY_TO_ONE);
Expand Down Expand Up @@ -154,7 +155,7 @@ private function addCustomFields(SchemaMap $map, Table $baseTable, string $entit
}
$fieldData = \CRM_Utils_SQL_Select::from('civicrm_custom_field f')
->join('custom_group', 'INNER JOIN civicrm_custom_group g ON g.id = f.custom_group_id')
->select(['g.name as custom_group_name', 'g.table_name', 'g.is_multiple', 'f.name', 'label', 'column_name', 'option_group_id'])
->select(['g.name as custom_group_name', 'g.table_name', 'g.is_multiple', 'f.name', 'f.data_type', 'label', 'column_name', 'option_group_id'])
->where('g.extends IN (@entity)', ['@entity' => $customInfo['extends']])
->where('g.is_active')
->where('f.is_active')
Expand Down Expand Up @@ -182,6 +183,11 @@ private function addCustomFields(SchemaMap $map, Table $baseTable, string $entit
$joinable = new Joinable($baseTable->getName(), $customInfo['column'], AllCoreTables::convertEntityNameToLower($entityName));
$customTable->addTableLink('entity_id', $joinable);
}

if ($fieldData->data_type === 'ContactReference') {
$joinable = new Joinable('civicrm_contact', 'id', $fieldData->name);
$customTable->addTableLink($fieldData->column_name, $joinable);
}
}

foreach ($links as $alias => $link) {
Expand Down
15 changes: 12 additions & 3 deletions ext/search/Civi/Search/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,20 @@ public static function getSchema() {
if (in_array('DAOEntity', $entity['type'], TRUE) && !in_array('EntityBridge', $entity['type'], TRUE)) {
foreach (array_reverse($entity['fields'], TRUE) as $index => $field) {
if (!empty($field['fk_entity']) && !$field['options'] && !empty($schema[$field['fk_entity']]['label_field'])) {
// The original field will get title instead of label since it represents the id (title usually ends in ID but label does not)
$entity['fields'][$index]['label'] = $field['title'];
$isCustom = strpos($field['name'], '.');
// Custom fields: append "ID" to original field label
if ($isCustom) {
$entity['fields'][$index]['label'] .= ' ' . E::ts('Contact ID');
}
// DAO fields: use title instead of label since it represents the id (title usually ends in ID but label does not)
else {
$entity['fields'][$index]['label'] = $field['title'];
}
// Add the label field from the other entity to this entity's list of fields
$newField = \CRM_Utils_Array::findAll($schema[$field['fk_entity']]['fields'], ['name' => $schema[$field['fk_entity']]['label_field']])[0];
$newField['name'] = str_replace('_id', '', $field['name']) . '.' . $schema[$field['fk_entity']]['label_field'];
// Due to string manipulation in \Civi\Api4\Service\Schema\SchemaMapBuilder::addJoins()
$alias = $isCustom ? $field['name'] : str_replace('_id', '', $field['name']);
$newField['name'] = $alias . '.' . $schema[$field['fk_entity']]['label_field'];
$newField['label'] = $field['label'] . ' ' . $newField['label'];
array_splice($entity['fields'], $index, 0, [$newField]);
}
Expand Down
29 changes: 10 additions & 19 deletions ext/search/ang/crmSearchAdmin.module.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@
return new RegExp('^' + join.alias + '_\\d\\d').test(path);
});
if (!join) {
console.warn( 'Join ' + fullNameOrAlias + ' not found.');
return;
}
path = path.replace(join.alias + '_', '');
Expand Down Expand Up @@ -138,28 +137,20 @@
return result;
}
function getFieldAndJoin(fieldName, entityName) {
var dotSplit = fieldName.split('.'),
joinEntity = dotSplit.length > 1 ? dotSplit[0] : null,
name = _.last(dotSplit).split(':')[0],
var fieldPath = fieldName.split(':')[0],
dotSplit = fieldPath.split('.'),
name,
join,
field;
// Custom fields contain a dot in their fieldname
// If 3 segments, the first is the joinEntity and the last 2 are the custom field
if (dotSplit.length === 3) {
name = dotSplit[1] + '.' + name;
}
// If 2 segments, it's ambiguous whether this is a custom field or joined field. Search the main entity first.
if (dotSplit.length === 2) {
field = _.find(getEntity(entityName).fields, {name: dotSplit[0] + '.' + name});
if (field) {
field.baseEntity = entityName;
return {field: field};
// If 2 or more segments, the first might be the name of a join
if (dotSplit.length > 1) {
join = getJoin(dotSplit[0]);
if (join) {
dotSplit.shift();
entityName = join.entity;
}
}
if (joinEntity) {
join = getJoin(joinEntity);
entityName = getJoin(joinEntity).entity;
}
name = dotSplit.join('.');
field = _.find(getEntity(entityName).fields, {name: name});
if (!field && join && join.bridge) {
field = _.find(getEntity(join.bridge).fields, {name: name});
Expand Down

0 comments on commit 1cbd793

Please sign in to comment.