Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev/core#2313 SearchKit - Default join conditions #19429

Merged
merged 3 commits into from
Jan 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions CRM/Activity/DAO/ActivityContact.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Activity/ActivityContact.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
* (GenCodeChecksum:3f147b2507b1e11a7df971be191161d1)
* (GenCodeChecksum:1263921d2a6832e26c5a7e34c684e35b)
*/

/**
Expand Down Expand Up @@ -52,7 +52,7 @@ class CRM_Activity_DAO_ActivityContact extends CRM_Core_DAO {
public $contact_id;

/**
* Nature of this contact's role in the activity: 1 assignee, 2 creator, 3 focus or target.
* Determines the contact's role in the activity (source, target, or assignee).
*
* @var int
*/
Expand Down Expand Up @@ -146,15 +146,16 @@ public static function &fields() {
'record_type_id' => [
'name' => 'record_type_id',
'type' => CRM_Utils_Type::T_INT,
'title' => ts('Record Type ID'),
'description' => ts('Nature of this contact\'s role in the activity: 1 assignee, 2 creator, 3 focus or target.'),
'title' => ts('Activity Contact Type'),
'description' => ts('Determines the contact\'s role in the activity (source, target, or assignee).'),
'where' => 'civicrm_activity_contact.record_type_id',
'table_name' => 'civicrm_activity_contact',
'entity' => 'ActivityContact',
'bao' => 'CRM_Activity_BAO_ActivityContact',
'localizable' => 0,
'html' => [
'type' => 'Select',
'label' => ts("Contact Role"),
],
'pseudoconstant' => [
'optionGroupName' => 'activity_contacts',
Expand Down
8 changes: 7 additions & 1 deletion CRM/Contact/DAO/RelationshipCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*
* Generated from xml/schema/CRM/Contact/RelationshipCache.xml
* DO NOT EDIT. Generated by CRM_Core_CodeGen
* (GenCodeChecksum:ba039fcadc13e48749f965343301ec1d)
* (GenCodeChecksum:ec899f1ccb7f617701d7108dc4282691)
*/

/**
Expand Down Expand Up @@ -246,6 +246,9 @@ public static function &fields() {
'entity' => 'RelationshipCache',
'bao' => 'CRM_Contact_BAO_RelationshipCache',
'localizable' => 0,
'html' => [
'label' => ts("Relationship to contact"),
],
'pseudoconstant' => [
'callback' => 'CRM_Core_PseudoConstant::relationshipTypeOptions',
],
Expand Down Expand Up @@ -280,6 +283,9 @@ public static function &fields() {
'entity' => 'RelationshipCache',
'bao' => 'CRM_Contact_BAO_RelationshipCache',
'localizable' => 0,
'html' => [
'label' => ts("Relationship from contact"),
],
'pseudoconstant' => [
'callback' => 'CRM_Core_PseudoConstant::relationshipTypeOptions',
],
Expand Down
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
5 changes: 4 additions & 1 deletion ext/search/ang/crmSearchAdmin/compose/criteria.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
<fieldset ng-repeat="join in $ctrl.savedSearch.api_params.join">
<div class="form-inline">
<label for="crm-search-join-{{ $index }}">{{:: ts('With') }}</label>
<input id="crm-search-join-{{ $index }}" class="form-control huge" ng-model="join[0]" crm-ui-select="{placeholder: ' ', data: getJoinEntities}" ng-change="changeJoin($index)" />
<input id="crm-search-join-{{ $index }}" class="form-control huge" ng-model="join[0]" crm-ui-select="{placeholder: ' ', data: getJoinEntities}" disabled >
<select class="form-control" ng-model="join[1]" ng-options="o.k as o.v for o in ::joinTypes" ></select>
<button class="btn btn-xs btn-danger-outline" ng-click="$ctrl.clearParam('join', $index)" title="{{:: ts('Remove join') }}">
<i class="crm-i fa-trash" aria-hidden="true"></i>
</button>
</div>
<fieldset class="api4-clause-fieldset">
<crm-search-clause clauses="join" format="json" skip="2 + getJoin(join[0]).conditions.length" op="AND" label="{{ ts('If') }}" fields="fieldsForWhere" ></crm-search-clause>
Expand Down
12 changes: 3 additions & 9 deletions ext/search/ang/crmSearchAdmin/crmSearchAdmin.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,22 +245,16 @@
_.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();
}
$scope.controls.join = '';
});
};

$scope.changeJoin = function(idx) {
if (ctrl.savedSearch.api_params.join[idx][0]) {
ctrl.savedSearch.api_params.join[idx].length = 2;
loadFieldOptions();
} else {
ctrl.clearParam('join', idx);
}
};

$scope.changeGroupBy = function(idx) {
if (!ctrl.savedSearch.api_params.groupBy[idx]) {
ctrl.clearParam('groupBy', idx);
Expand Down
3 changes: 0 additions & 3 deletions ext/search/css/search.css
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@
right: 0;
top: 0;
}
#bootstrap-theme.crm-search crm-search-clause > .btn-group .btn {
border: 0 none;
}

#bootstrap-theme.crm-search fieldset div.api4-input {
margin-bottom: 10px;
Expand Down
5 changes: 3 additions & 2 deletions xml/schema/Activity/ActivityContact.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,14 @@
<field>
<name>record_type_id</name>
<type>int unsigned</type>
<title>Record Type ID</title>
<comment>Nature of this contact's role in the activity: 1 assignee, 2 creator, 3 focus or target.</comment>
<title>Activity Contact Type</title>
<comment>Determines the contact's role in the activity (source, target, or assignee).</comment>
<pseudoconstant>
<optionGroupName>activity_contacts</optionGroupName>
</pseudoconstant>
<html>
<type>Select</type>
<label>Contact Role</label>
</html>
<add>4.4</add>
</field>
Expand Down
6 changes: 6 additions & 0 deletions xml/schema/Contact/RelationshipCache.xml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@
<length>64</length>
<comment>name for relationship of near_contact to far_contact.</comment>
<add>5.29</add>
<html>
<label>Relationship to contact</label>
</html>
<pseudoconstant>
<callback>CRM_Core_PseudoConstant::relationshipTypeOptions</callback>
</pseudoconstant>
Expand Down Expand Up @@ -124,6 +127,9 @@
<length>64</length>
<comment>name for relationship of far_contact to near_contact.</comment>
<add>5.29</add>
<html>
<label>Relationship from contact</label>
</html>
<pseudoconstant>
<callback>CRM_Core_PseudoConstant::relationshipTypeOptions</callback>
</pseudoconstant>
Expand Down