Skip to content

Commit

Permalink
SearchKit - Default join conditions
Browse files Browse the repository at this point in the history
Adds @ui_join_filters annotations to APIv4 entities which automatically shows that field when adding a join

https://lab.civicrm.org/dev/core/-/issues/2313
  • Loading branch information
colemanw committed Jan 21, 2021
1 parent dca7262 commit 2f61656
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 12 deletions.
7 changes: 4 additions & 3 deletions Civi/Api4/ActivityContact.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@
namespace Civi\Api4;

/**
* ActivityContact Entity.
* ActivityContact BridgeEntity.
*
* This entity adds a record which relate a contact to activity.
* This connects a contact to an activity.
*
* Creating a new ActivityContact requires at minimum a contact_id and activity_id.
* The record_type_id field determines the contact's role in the activity (source, target, or assignee).
* @ui_join_filters record_type_id
*
* @see \Civi\Api4\Activity
* @package Civi\Api4
Expand Down
2 changes: 2 additions & 0 deletions Civi/Api4/Address.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
* Creating a new address requires at minimum a contact's ID and location type ID
* and other attributes (although optional) like street address, city, country etc.
*
* @ui_join_filters location_type_id
*
* @package Civi\Api4
*/
class Address extends Generic\DAOEntity {
Expand Down
5 changes: 5 additions & 0 deletions Civi/Api4/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ public static function getFields($checkPermissions = TRUE) {
'data_type' => 'Array',
'description' => 'Connecting fields for EntityBridge types',
],
[
'name' => 'ui_join_filters',
'data_type' => 'Array',
'description' => 'When joining entities in the UI, which fields should be presented by default in the ON clause',
],
];
}))->setCheckPermissions($checkPermissions);
}
Expand Down
1 change: 1 addition & 0 deletions Civi/Api4/RelationshipCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*
* @see \Civi\Api4\Relationship
* @bridge near_contact_id far_contact_id
* @ui_join_filters near_relation
* @package Civi\Api4
*/
class RelationshipCache extends Generic\AbstractEntity {
Expand Down
4 changes: 2 additions & 2 deletions Civi/Api4/Utils/ReflectionUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ public static function parseDocBlock($comment) {
elseif ($key == 'return') {
$info['return'] = explode('|', $words[0]);
}
elseif ($key == 'options') {
elseif ($key == 'options' || $key == 'ui_join_filters') {
$val = str_replace(', ', ',', implode(' ', $words));
$info['options'] = explode(',', $val);
$info[$key] = explode(',', $val);
}
elseif ($key == 'throws' || $key == 'see') {
$info[$key][] = implode(' ', $words);
Expand Down
32 changes: 31 additions & 1 deletion ext/search/Civi/Search/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public static function getOperators():array {
public static function getSchema() {
$schema = [];
$entities = \Civi\Api4\Entity::get()
->addSelect('name', 'title', 'type', 'title_plural', 'description', 'icon', 'paths', 'dao', 'bridge')
->addSelect('name', 'title', 'type', 'title_plural', 'description', 'icon', 'paths', 'dao', 'bridge', 'ui_join_filters')
->addWhere('searchable', '=', TRUE)
->addOrderBy('title_plural')
->setChain([
Expand Down Expand Up @@ -142,6 +142,7 @@ public static function getJoins(array $allowedEntities) {
) {
continue;
}
// For dynamic references getTargetEntities will return multiple targets; for normal joins this loop will only run once
foreach ($reference->getTargetEntities() as $targetTable => $targetEntityName) {
if (!isset($allowedEntities[$targetEntityName]) || $targetEntityName === $entity['name']) {
continue;
Expand All @@ -158,6 +159,7 @@ public static function getJoins(array $allowedEntities) {
'description' => $dynamicCol ? '' : $keyField['label'],
'entity' => $targetEntityName,
'conditions' => self::getJoinConditions($keyField['name'], $alias . '.' . $reference->getTargetKey(), $targetTable, $dynamicCol),
'defaults' => self::getJoinDefaults($alias, $targetEntity),
'alias' => $alias,
'multi' => FALSE,
];
Expand All @@ -168,6 +170,7 @@ public static function getJoins(array $allowedEntities) {
'description' => $dynamicCol ? '' : $keyField['label'],
'entity' => $entity['name'],
'conditions' => self::getJoinConditions($reference->getTargetKey(), $alias . '.' . $keyField['name'], $targetTable, $dynamicCol ? $alias . '.' . $dynamicCol : NULL),
'defaults' => self::getJoinDefaults($alias, $entity),
'alias' => $alias,
'multi' => TRUE,
];
Expand All @@ -192,6 +195,7 @@ public static function getJoins(array $allowedEntities) {
[$bridge],
self::getJoinConditions('id', $alias . '.' . $baseKey, NULL, NULL)
),
'defaults' => self::getJoinDefaults($alias, $targetEntity, $entity),
'bridge' => $bridge,
'alias' => $alias,
'multi' => TRUE,
Expand All @@ -206,6 +210,7 @@ public static function getJoins(array $allowedEntities) {
[$bridge],
self::getJoinConditions($reference->getTargetKey(), $alias . '.' . $keyField['name'], $targetTable, $dynamicCol ? $alias . '.' . $dynamicCol : NULL)
),
'defaults' => self::getJoinDefaults($alias, $baseEntity, $entity),
'bridge' => $bridge,
'alias' => $alias,
'multi' => TRUE,
Expand Down Expand Up @@ -246,4 +251,29 @@ private static function getJoinConditions($nearCol, $farCol, $targetTable, $dyna
return $conditions;
}

/**
* @param $alias
* @param array ...$entities
* @return array
*/
private static function getJoinDefaults($alias, ...$entities):array {
$conditions = [];
foreach ($entities as $entity) {
foreach ($entity['ui_join_filters'] ?? [] as $fieldName) {
$field = civicrm_api4($entity['name'], 'getFields', [
'select' => ['options'],
'where' => [['name', '=', $fieldName]],
'loadOptions' => ['name'],
])->first();
$value = isset($field['options'][0]) ? json_encode($field['options'][0]['name']) : '';
$conditions[] = [
$alias . '.' . $fieldName . ($value ? ':name' : ''),
'=',
$value,
];
}
}
return $conditions;
}

}
16 changes: 10 additions & 6 deletions ext/search/ang/crmSearchAdmin.module.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,21 @@
// Add the numbered suffix to the join conditions
// If this is a deep join, also add the base entity prefix
var prefix = alias.replace(new RegExp('_?' + join.alias + '_?\\d?\\d?$'), '');
_.each(result.conditions, function(condition) {
function replaceRefs(condition) {
if (_.isArray(condition)) {
_.each(condition, function(ref, side) {
if (side !== 1 && _.includes(ref, '.')) {
condition[side] = ref.replace(join.alias + '.', alias + '.');
} else if (side !== 1 && prefix.length && !_.includes(ref, '"') && !_.includes(ref, "'")) {
condition[side] = prefix + '.' + ref;
if (side !== 1 && typeof ref === 'string') {
if (_.includes(ref, '.')) {
condition[side] = ref.replace(join.alias + '.', alias + '.');
} else if (prefix.length && !_.includes(ref, '"') && !_.includes(ref, "'")) {
condition[side] = prefix + '.' + ref;
}
}
});
}
});
}
_.each(result.conditions, replaceRefs);
_.each(result.defaults, replaceRefs);
return result;
}
function getFieldAndJoin(fieldName, entityName) {
Expand Down
3 changes: 3 additions & 0 deletions ext/search/ang/crmSearchAdmin/crmSearchAdmin.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@
_.each(_.cloneDeep(join.conditions), function(condition) {
params.push(condition);
});
_.each(_.cloneDeep(join.defaults), function(condition) {
params.push(condition);
});
ctrl.savedSearch.api_params.join.push(params);
loadFieldOptions();
}
Expand Down

0 comments on commit 2f61656

Please sign in to comment.