+--------------------------------------------------------------------+
*/
+use Civi\Api4\Query\SqlExpression;
+
/**
*
* @package CRM
*/
protected static function getApiSQL(array $savedSearch, string $addSelect, string $excludeClause) {
$apiParams = $savedSearch['api_params'] + ['select' => ['id'], 'checkPermissions' => FALSE];
- list($idField) = explode(' AS ', $apiParams['select'][0]);
- $apiParams['select'] = [
- $addSelect,
- $idField,
- ];
+ $idField = SqlExpression::convert($apiParams['select'][0], TRUE)->getAlias();
+ // Unless there's a HAVING clause, we don't care about other columns
+ if (empty($apiParams['having'])) {
+ $apiParams['select'] = array_slice($apiParams['select'], 0, 1);
+ }
$api = \Civi\API\Request::create($savedSearch['api_entity'], 'get', $apiParams);
$query = new \Civi\Api4\Query\Api4SelectQuery($api);
$query->forceSelectId = FALSE;
$query->getQuery()->having("$idField $excludeClause");
- return $query->getSql();
+ $sql = $query->getSql();
+ // Place sql in a nested sub-query, otherwise HAVING is impossible on any field other than contact_id
+ return "SELECT $addSelect, `$idField` AS contact_id FROM ($sql) api_query";
}
/**
'header',
// https://lab.civicrm.org/dev/core/issues/1286
'footer',
+ // SavedSearch entity
+ 'api_params',
];
$custom = CRM_Core_DAO::executeQuery('SELECT id FROM civicrm_custom_field WHERE html_type = "RichTextEditor"');
while ($custom->fetch()) {
}
// Pick the first applicable column for contact id
- model.api_params.select[0] = _.intersection(model.api_params.select, _.pluck($scope.columns, 'id'))[0] || $scope.columns[0].name;
- model.api_params.select.length = 1;
+ model.api_params.select.unshift(_.intersection(model.api_params.select, _.pluck($scope.columns, 'id'))[0] || $scope.columns[0].id);
if (!CRM.checkPerm('administer reserved groups')) {
$scope.groupEntityRefParams.api.params.is_reserved = 0;
group.visibility = model.visibility;
group.group_type = model.group_type;
group.saved_search_id = '$id';
+ model.api_params.select = _.unique(model.api_params.select);
var savedSearch = {
api_entity: model.api_entity,
api_params: model.api_params
api_params: _.cloneDeep(angular.extend({}, ctrl.params, {version: 4}))
};
delete model.api_params.orderBy;
- if (ctrl.load && ctrl.load.api_params) {
- model.api_params.select = ctrl.load.api_params.select;
+ if (ctrl.load && ctrl.load.api_params && ctrl.load.api_params.select && ctrl.load.api_params.select[0]) {
+ model.api_params.select.unshift(ctrl.load.api_params.select[0]);
}
var options = CRM.utils.adjustDialogDefaults({
autoOpen: false,
<form id="bootstrap-theme">
<div ng-controller="SaveSmartGroup">
- <div crm-ui-debug="model"></div>
<input class="form-control" id="api-save-search-select-group" ng-model="model.id" crm-entityref="groupEntityRefParams" >
<label ng-show="!model.id">{{:: ts('Or') }}</label>
<input class="form-control" placeholder="{{:: ts('Create new group') }}" ng-model="model.title" ng-show="!model.id">
$this->assertArrayNotHasKey($out['id'], $ins['values']);
}
+ public function testSmartGroupWithHaving() {
+ $in = Contact::create(FALSE)->addValue('first_name', 'yes')->addValue('last_name', 'siree')->execute()->first();
+ $in2 = Contact::create(FALSE)->addValue('first_name', 'yessir')->addValue('last_name', 'ee')->execute()->first();
+ $out = Contact::create(FALSE)->addValue('first_name', 'yess')->execute()->first();
+
+ $savedSearch = civicrm_api4('SavedSearch', 'create', [
+ 'values' => [
+ 'api_entity' => 'Contact',
+ 'api_params' => [
+ 'version' => 4,
+ 'select' => ['id', 'CONCAT(first_name, last_name) AS whole_name'],
+ 'where' => [
+ ['id', '>=', $in['id']],
+ ],
+ 'having' => [
+ ['whole_name', '=', 'yessiree'],
+ ],
+ ],
+ ],
+ 'chain' => [
+ 'group' => ['Group', 'create', ['values' => ['title' => 'Having Test', 'saved_search_id' => '$id']], 0],
+ ],
+ ])->first();
+
+ // Oops we don't have an api4 syntax yet for selecting contacts in a group.
+ $ins = civicrm_api3('Contact', 'get', ['group' => $savedSearch['group']['name'], 'options' => ['limit' => 0]]);
+ $this->assertCount(2, $ins['values']);
+ $this->assertArrayHasKey($in['id'], $ins['values']);
+ $this->assertArrayHasKey($in2['id'], $ins['values']);
+ $this->assertArrayNotHasKey($out['id'], $ins['values']);
+ }
+
}