Skip to content

Commit

Permalink
Merge pull request #19429 from colemanw/searchJoinDefaults
Browse files Browse the repository at this point in the history
dev/core#2313 SearchKit - Default join conditions
  • Loading branch information
eileenmcnaughton authored Jan 22, 2021
2 parents 444dadc + 4df8a1d commit c986f42
Show file tree
Hide file tree
Showing 14 changed files with 83 additions and 32 deletions.
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

0 comments on commit c986f42

Please sign in to comment.