diff --git a/Civi/Api4/Generic/AbstractAction.php b/Civi/Api4/Generic/AbstractAction.php
index 08daf23954f7..a531cddc72d4 100644
--- a/Civi/Api4/Generic/AbstractAction.php
+++ b/Civi/Api4/Generic/AbstractAction.php
@@ -430,9 +430,6 @@ public function getPermissions() {
public function entityFields() {
if (!$this->_entityFields) {
$allowedTypes = ['Field', 'Filter', 'Extra'];
- if (method_exists($this, 'getCustomGroup')) {
- $allowedTypes[] = 'Custom';
- }
$getFields = \Civi\API\Request::create($this->getEntityName(), 'getFields', [
'version' => 4,
'checkPermissions' => FALSE,
diff --git a/Civi/Api4/Query/Api4SelectQuery.php b/Civi/Api4/Query/Api4SelectQuery.php
index ff1590c32e7e..aee952cc6b7e 100644
--- a/Civi/Api4/Query/Api4SelectQuery.php
+++ b/Civi/Api4/Query/Api4SelectQuery.php
@@ -722,12 +722,14 @@ private function addExplicitJoins() {
$joinEntityFields = $joinEntityGet->entityFields();
foreach ($joinEntityFields as $field) {
$field['sql_name'] = '`' . $alias . '`.`' . $field['column_name'] . '`';
+ $field['explicit_join'] = $alias;
$this->addSpecField($alias . '.' . $field['name'], $field);
}
$tableName = CoreUtil::getTableName($entity);
// Save join info to be retrieved by $this->getExplicitJoin()
$this->explicitJoins[$alias] = [
'entity' => $entity,
+ 'alias' => $alias,
'table' => $tableName,
'bridge' => NULL,
];
@@ -938,6 +940,7 @@ private function registerBridgeJoinFields($bridgeEntity, $joinRef, $baseRef, str
// For INNER joins, these fields get a sql alias pointing to the bridge entity,
// but an api alias pretending they belong to the join entity.
$field['sql_name'] = '`' . ($side === 'LEFT' ? $alias : $bridgeAlias) . '`.`' . $field['column_name'] . '`';
+ $field['explicit_join'] = $alias;
$this->addSpecField($alias . '.' . $name, $field);
if ($field['type'] === 'Field') {
$fakeFields[$field['column_name']] = '`' . $bridgeAlias . '`.`' . $field['column_name'] . '`';
@@ -1094,6 +1097,8 @@ protected function autoJoinFK($key) {
else {
$fieldArray['sql_name'] = '`' . $baseTableAlias . '`.`' . $link->getBaseColumn() . '`';
}
+ $fieldArray['implicit_join'] = $link->getBaseColumn();
+ $fieldArray['explicit_join'] = $explicitJoin ? $explicitJoin['alias'] : NULL;
// Custom fields will already have the group name prefixed
$fieldName = $isCustom ? explode('.', $fieldArray['name'])[1] : $fieldArray['name'];
$this->addSpecField($joinTreeNode[$joinName]['#path'] . $fieldName, $fieldArray);
@@ -1252,7 +1257,10 @@ private function addSpecField($path, $field) {
$this->apiFieldSpec[$path] = FALSE;
return;
}
- $this->apiFieldSpec[$path] = $field;
+ $this->apiFieldSpec[$path] = $field + [
+ 'implicit_join' => NULL,
+ 'explicit_join' => NULL,
+ ];
}
/**
diff --git a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php
index a9e48d58c112..d807e3447d61 100644
--- a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php
+++ b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php
@@ -275,10 +275,64 @@ private function getUrl(string $path) {
return \CRM_Utils_System::url($path, NULL, $absolute, NULL, FALSE);
}
+ /**
+ * @param $column
+ * @param $data
+ * @return array{entity: string, input_type: string, data_type: string, options: bool, serialize: bool, fk_entity: string, value_key: string, record: array, value: mixed}|null
+ */
private function formatEditableColumn($column, $data) {
+ $editable = $this->getEditableInfo($column['key']);
+ if (!empty($data[$editable['id_path']])) {
+ $editable['record'] = [
+ $editable['id_key'] => $data[$editable['id_path']],
+ ];
+ $editable['value'] = $data[$editable['value_path']];
+ \CRM_Utils_Array::remove($editable, 'id_key', 'id_path', 'value_path');
+ return $editable;
+ }
+ return NULL;
+ }
+ /**
+ * @param $key
+ * @return array{entity: string, input_type: string, data_type: string, options: bool, serialize: bool, fk_entity: string, value_key: string, value_path: string, id_key: string, id_path: string}|null
+ */
+ private function getEditableInfo($key) {
+ [$key] = explode(':', $key);
+ $field = $this->getField($key);
+ // If field is an implicit join, use the original fk field
+ if (!empty($field['implicit_join'])) {
+ return $this->getEditableInfo(substr($key, 0, -1 - strlen($field['name'])));
+ }
+ if ($field) {
+ $idKey = CoreUtil::getIdFieldName($field['entity']);
+ $idPath = ($field['explicit_join'] ? $field['explicit_join'] . '.' : '') . $idKey;
+ // Hack to support editing relationships
+ if ($field['entity'] === 'RelationshipCache') {
+ $field['entity'] = 'Relationship';
+ $idPath = ($field['explicit_join'] ? $field['explicit_join'] . '.' : '') . 'relationship_id';
+ }
+ return [
+ 'entity' => $field['entity'],
+ 'input_type' => $field['input_type'],
+ 'data_type' => $field['data_type'],
+ 'options' => !empty($field['options']),
+ 'serialize' => !empty($field['serialize']),
+ 'fk_entity' => $field['fk_entity'],
+ 'value_key' => $field['name'],
+ 'value_path' => $key,
+ 'id_key' => $idKey,
+ 'id_path' => $idPath,
+ ];
+ }
+ return NULL;
}
+ /**
+ * @param $column
+ * @param $data
+ * @return array{url: string, width: int, height: int}
+ */
private function formatImage($column, $data) {
$tokenExpr = $column['rewrite'] ?: '[' . $column['key'] . ']';
return [
@@ -575,10 +629,13 @@ protected function augmentSelectClause(&$apiParams): void {
$possibleTokens .= implode('', array_column($column['links'], 'text'));
}
- // Select value fields for in-place editing
- if (isset($column['editable']['value'])) {
- $additions[] = $column['editable']['value'];
- $additions[] = $column['editable']['id'];
+ // Select id & value for in-place editing
+ if (!empty($column['editable'])) {
+ $editable = $this->getEditableInfo($column['key']);
+ if ($editable) {
+ $additions[] = $editable['value_path'];
+ $additions[] = $editable['id_path'];
+ }
}
}
// Add fields referenced via token
diff --git a/ext/search_kit/Civi/Search/Admin.php b/ext/search_kit/Civi/Search/Admin.php
index 1e05fa1a5717..5a912e3c7d68 100644
--- a/ext/search_kit/Civi/Search/Admin.php
+++ b/ext/search_kit/Civi/Search/Admin.php
@@ -122,7 +122,6 @@ public static function getSchema() {
$field['fieldName'] = $field['name'];
// Hack for RelationshipCache to make Relationship fields editable
if ($entity['name'] === 'RelationshipCache') {
- $entity['primary_key'] = ['relationship_id'];
if (in_array($field['name'], ['is_active', 'start_date', 'end_date'])) {
$field['readonly'] = FALSE;
}
diff --git a/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminDisplay.component.js b/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminDisplay.component.js
index 22219d66720d..9aea30e3d93a 100644
--- a/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminDisplay.component.js
+++ b/ext/search_kit/ang/crmSearchAdmin/crmSearchAdminDisplay.component.js
@@ -156,37 +156,12 @@
this.toggleEditable = function(col) {
if (col.editable) {
delete col.editable;
- return;
- }
-
- var info = searchMeta.parseExpr(col.key),
- arg = _.findWhere(info.args, {type: 'field'}) || {},
- value = col.key.split(':')[0];
- if (!arg.field || info.fn) {
- delete col.editable;
- return;
- }
- // If field is an implicit join, use the original fk field
- if (arg.field.name !== arg.field.fieldName) {
- value = value.substr(0, value.lastIndexOf('.'));
- info = searchMeta.parseExpr(value);
- arg = info.args[0];
+ } else {
+ col.editable = true;
}
- col.editable = {
- // Hack to support editing relationships
- entity: arg.field.entity.replace('RelationshipCache', 'Relationship'),
- input_type: arg.field.input_type,
- data_type: arg.field.data_type,
- options: !!arg.field.options,
- serialize: !!arg.field.serialize,
- fk_entity: arg.field.fk_entity,
- id: arg.prefix + searchMeta.getEntity(arg.field.entity).primary_key[0],
- name: arg.field.name,
- value: value
- };
};
- this.isEditable = function(col) {
+ this.canBeEditable = function(col) {
var expr = ctrl.getExprFromSelect(col.key),
info = searchMeta.parseExpr(expr);
return !col.image && !col.rewrite && !col.link && !info.fn && info.args[0] && info.args[0].field && !info.args[0].field.readonly;
@@ -213,6 +188,7 @@
if (column.link) {
ctrl.onChangeLink(column, column.link.path, '');
} else {
+ delete column.editable;
var defaultLink = ctrl.getLinks(column.key)[0];
column.link = {path: defaultLink ? defaultLink.path : 'civicrm/'};
ctrl.onChangeLink(column, null, column.link.path);
diff --git a/ext/search_kit/ang/crmSearchAdmin/displays/colType/field.html b/ext/search_kit/ang/crmSearchAdmin/displays/colType/field.html
index 801c3d310830..414eba6b30fc 100644
--- a/ext/search_kit/ang/crmSearchAdmin/displays/colType/field.html
+++ b/ext/search_kit/ang/crmSearchAdmin/displays/colType/field.html
@@ -43,11 +43,11 @@