diff --git a/CRM/Contact/DAO/RelationshipCache.php b/CRM/Contact/DAO/RelationshipCache.php
index 33fdc4ebec94..c1ddd69b816a 100644
--- a/CRM/Contact/DAO/RelationshipCache.php
+++ b/CRM/Contact/DAO/RelationshipCache.php
@@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Contact/RelationshipCache.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:79cb98a7730bede29ea2cf1aeb5a780e)
+ * (GenCodeChecksum:3f113a0869fa2a649d0e6044a8e59572)
*/
/**
@@ -305,6 +305,7 @@ public static function &fields() {
'bao' => 'CRM_Contact_BAO_RelationshipCache',
'localizable' => 0,
'html' => [
+ 'type' => 'Select',
'label' => ts("Relationship to contact"),
],
'pseudoconstant' => [
@@ -345,6 +346,7 @@ public static function &fields() {
'bao' => 'CRM_Contact_BAO_RelationshipCache',
'localizable' => 0,
'html' => [
+ 'type' => 'Select',
'label' => ts("Relationship from contact"),
],
'pseudoconstant' => [
@@ -419,6 +421,7 @@ public static function &fields() {
'FKClassName' => 'CRM_Case_DAO_Case',
'component' => 'CiviCase',
'html' => [
+ 'type' => 'EntityRef',
'label' => ts("Case"),
],
'readonly' => TRUE,
diff --git a/ext/afform/admin/Civi/Api4/Action/Afform/LoadAdminData.php b/ext/afform/admin/Civi/Api4/Action/Afform/LoadAdminData.php
index 1bcba8155227..c8255525a1da 100644
--- a/ext/afform/admin/Civi/Api4/Action/Afform/LoadAdminData.php
+++ b/ext/afform/admin/Civi/Api4/Action/Afform/LoadAdminData.php
@@ -195,11 +195,18 @@ public function _run(\Civi\Api4\Generic\Result $result) {
$entities[] = $display['saved_search_id.api_entity'];
foreach ($display['saved_search_id.api_params']['join'] ?? [] as $join) {
$entities[] = explode(' AS ', $join[0])[0];
+ // Add bridge entities (but only if they are tagged searchable e.g. RelationshipCache)
+ if (is_string($join[2] ?? NULL) &&
+ in_array(CoreUtil::getInfoItem($join[2], 'searchable'), ['primary', 'secondary'])
+ ) {
+ $entities[] = $join[2];
+ }
}
}
if (!$newForm) {
$scanBlocks($info['definition']['layout']);
}
+ $entities = array_unique($entities);
$this->loadAvailableBlocks($entities, $info, [['join_entity', 'IS NULL']]);
}
diff --git a/ext/afform/admin/ang/afGuiEditor/afGuiSearch.component.js b/ext/afform/admin/ang/afGuiEditor/afGuiSearch.component.js
index d6f93f6c073a..04c006921a78 100644
--- a/ext/afform/admin/ang/afGuiEditor/afGuiSearch.component.js
+++ b/ext/afform/admin/ang/afGuiEditor/afGuiSearch.component.js
@@ -101,18 +101,32 @@
label: mainEntity.label,
fields: mainEntity.fields
}];
- entityCount[mainEntity.entity] = 1;
+
+ // Increment count of entityName and return a suffix string if > 1
+ function countEntity(entityName) {
+ entityCount[entityName] = (entityCount[entityName] || 0) + 1;
+ return entityCount[entityName] > 1 ? ' ' + entityCount[entityName] : '';
+ }
+ countEntity(mainEntity.entity);
_.each(ctrl.display.settings['saved_search_id.api_params'].join, function(join) {
var joinInfo = join[0].split(' AS '),
- entity = afGui.getEntity(joinInfo[0]);
- entityCount[entity.entity] = (entityCount[entity.entity] || 0) + 1;
+ entity = afGui.getEntity(joinInfo[0]),
+ joinEntity = afGui.getEntity(join[2]);
entities.push({
name: entity.entity,
prefix: joinInfo[1] + '.',
- label: entity.label + (entityCount[entity.entity] > 1 ? ' ' + entityCount[entity.entity] : ''),
+ label: entity.label + countEntity(entity.entity),
fields: entity.fields,
});
+ if (joinEntity) {
+ entities.push({
+ name: joinEntity.entity,
+ prefix: joinInfo[1] + '.',
+ label: joinEntity.label + countEntity(joinEntity.entity),
+ fields: _.omit(joinEntity.fields, _.keys(entity.fields)),
+ });
+ }
});
return entities;
diff --git a/ext/afform/admin/ang/afGuiEditor/elements/afGuiContainer.component.js b/ext/afform/admin/ang/afGuiEditor/elements/afGuiContainer.component.js
index 8a0d0a0e1139..ba9d313f9577 100644
--- a/ext/afform/admin/ang/afGuiEditor/elements/afGuiContainer.component.js
+++ b/ext/afform/admin/ang/afGuiEditor/elements/afGuiContainer.component.js
@@ -400,7 +400,7 @@
};
// Returns the entity type for fields within this conainer (join entity type if this is a join, else the primary entity type)
- this.getFieldEntityType = function(fieldName) {
+ this.getFieldEntityType = function(fieldKey) {
var entityType;
// If entityName is declared for this fieldset, return entity-type or join-type
if (ctrl.entityName) {
@@ -409,17 +409,22 @@
} else {
var searchKey = ctrl.getDataEntity(),
searchDisplay = afGui.getSearchDisplay.apply(null, searchKey.split('.')),
- prefix = _.includes(fieldName, '.') ? fieldName.split('.')[0] : null;
+ fieldName = fieldKey.substr(fieldKey.indexOf('.') + 1),
+ prefix = _.includes(fieldKey, '.') ? fieldKey.split('.')[0] : null;
if (prefix) {
_.each(searchDisplay['saved_search_id.api_params'].join, function(join) {
var joinInfo = join[0].split(' AS ');
if (prefix === joinInfo[1]) {
entityType = joinInfo[0];
+ // If entity doesn't contain field, it belongs to the bridge join
+ if (!(fieldName in afGui.getEntity(entityType).fields)) {
+ entityType = join[2];
+ }
return false;
}
});
}
- if (!entityType && fieldName && afGui.getField(searchDisplay['saved_search_id.api_entity'], fieldName)) {
+ if (!entityType && fieldKey && afGui.getField(searchDisplay['saved_search_id.api_entity'], fieldKey)) {
entityType = searchDisplay['saved_search_id.api_entity'];
}
}
diff --git a/ext/afform/core/Civi/Afform/AfformMetadataInjector.php b/ext/afform/core/Civi/Afform/AfformMetadataInjector.php
index b84bdfb324c7..c30c009c014b 100644
--- a/ext/afform/core/Civi/Afform/AfformMetadataInjector.php
+++ b/ext/afform/core/Civi/Afform/AfformMetadataInjector.php
@@ -77,14 +77,19 @@ public static function preprocess($e) {
/**
* Merge field definition metadata into an afform field's definition
*
- * @param string $entityName
+ * @param string|array $entityNames
* @param string $action
* @param \DOMElement $afField
* @throws \API_Exception
*/
- private static function fillFieldMetadata($entityName, $action, \DOMElement $afField) {
+ private static function fillFieldMetadata($entityNames, $action, \DOMElement $afField) {
$fieldName = $afField->getAttribute('name');
- $fieldInfo = self::getField($entityName, $fieldName, $action);
+ foreach ((array) $entityNames as $entityName) {
+ $fieldInfo = self::getField($entityName, $fieldName, $action);
+ if ($fieldInfo) {
+ break;
+ }
+ }
// Merge field definition data with whatever's already in the markup.
$deep = ['input_attrs'];
if ($fieldInfo) {
@@ -179,6 +184,9 @@ private static function getField(string $entityName, string $fieldName, string $
break;
}
}
+ if (!isset($field)) {
+ return NULL;
+ }
// Id field for selecting existing entity
if ($action === 'update' && $field['name'] === CoreUtil::getIdFieldName($entityName)) {
$entityTitle = CoreUtil::getInfoItem($entityName, 'title');
@@ -200,24 +208,28 @@ private static function getField(string $entityName, string $fieldName, string $
}
/**
- * Determines name of the api entity based on the field name prefix
+ * Determines name of the api entit(ies) based on the field name prefix
+ *
+ * Note: Normally will return a single entity name, but
+ * Will return 2 entity names in the case of Bridge joins e.g. RelationshipCache
*
* @param string $fieldName
* @param string[] $entityList
- * @return string
+ * @return string|array
*/
private static function getFieldEntityType($fieldName, $entityList) {
$prefix = strpos($fieldName, '.') ? explode('.', $fieldName)[0] : NULL;
+ $joinEntities = [];
$baseEntity = array_shift($entityList);
if ($prefix) {
foreach ($entityList as $entityAndAlias) {
[$entity, $alias] = explode(' AS ', $entityAndAlias);
if ($alias === $prefix) {
- return $entityAndAlias;
+ $joinEntities[] = $entityAndAlias;
}
}
}
- return $baseEntity;
+ return $joinEntities ?: $baseEntity;
}
private static function getFormEntities(\phpQueryObject $doc) {
diff --git a/ext/search_kit/Civi/Search/AfformSearchMetadataInjector.php b/ext/search_kit/Civi/Search/AfformSearchMetadataInjector.php
index 98244fe9d74e..478c491d2e67 100644
--- a/ext/search_kit/Civi/Search/AfformSearchMetadataInjector.php
+++ b/ext/search_kit/Civi/Search/AfformSearchMetadataInjector.php
@@ -57,7 +57,13 @@ public static function preprocess($e) {
// Add entity names to the fieldset so that afform can populate field metadata
$fieldset = pq($component)->parents('[af-fieldset]');
if ($fieldset->length) {
- $entityList = array_merge([$display['saved_search_id.api_entity']], array_column($display['saved_search_id.api_params']['join'] ?? [], 0));
+ $entityList = [$display['saved_search_id.api_entity']];
+ foreach ($display['saved_search_id.api_params']['join'] ?? [] as $join) {
+ $entityList[] = $join[0];
+ if (is_string($join[2] ?? NULL)) {
+ $entityList[] = $join[2] . ' AS ' . (explode(' AS ', $join[0])[1]);
+ }
+ }
$fieldset->attr('api-entities', htmlspecialchars(\CRM_Utils_JS::encode($entityList)));
}
}
diff --git a/xml/schema/Contact/RelationshipCache.xml b/xml/schema/Contact/RelationshipCache.xml
index 62d9ea1d2fbb..7421611dbcff 100644
--- a/xml/schema/Contact/RelationshipCache.xml
+++ b/xml/schema/Contact/RelationshipCache.xml
@@ -115,6 +115,7 @@
5.29
+ Select
CRM_Core_PseudoConstant::relationshipTypeOptions
@@ -152,6 +153,7 @@
5.29
+ Select
CRM_Core_PseudoConstant::relationshipTypeOptions
@@ -237,6 +239,7 @@
FK to civicrm_case
+ EntityRef
5.44
true