$scope.loading = false;
$scope.controls = {};
$scope.langs = ['php', 'js', 'ang', 'cli'];
- $scope.joinTypes = [{k: false, v: ts('Optional')}, {k: true, v: ts('Required')}];
+ $scope.joinTypes = [{k: false, v: 'FALSE (LEFT JOIN)'}, {k: true, v: 'TRUE (INNER JOIN)'}];
+ $scope.bridgeEntities = _.filter(schema, {type: 'BridgeEntity'});
$scope.code = {
php: [
{name: 'oop', label: ts('OOP Style'), code: ''},
{name: 'ang2', label: ts('Batch Calls'), code: ''}
],
cli: [
- {name: 'cv', label: ts('CV'), code: ''}
+ {name: 'short', label: ts('CV (short)'), code: ''},
+ {name: 'long', label: ts('CV (long)'), code: ''},
+ {name: 'pipe', label: ts('CV (pipe)'), code: ''}
]
};
function pluralize(str) {
var lastLetter = str[str.length - 1],
lastTwo = str[str.length - 2] + lastLetter;
- if (lastLetter === 's' || lastTwo === 'ch') {
+ if (lastLetter === 's' || lastLetter === 'x' || lastTwo === 'ch') {
return str + 'es';
}
if (lastLetter === 'y' && lastTwo !== 'ey') {
return _.findWhere(schema, {name: entityName || $scope.entity});
}
+ // Get name of entity given join alias
+ function entityNameFromAlias(alias) {
+ var joins = getExplicitJoins(),
+ entity = $scope.entity,
+ path = alias.split('.');
+ // First check explicit joins
+ if (joins[alias]) {
+ return joins[alias];
+ }
+ // Then lookup implicit links
+ _.each(path, function(node) {
+ var link = _.find(links[entity], {alias: node});
+ if (!link) {
+ return false;
+ }
+ entity = link.entity;
+ });
+ return entity;
+ }
+
// Get all params that have been set
function getParams() {
var params = {};
addJoins($scope.fieldsAndJoinsAndFunctionsWithSuffixes, false, ['name', 'label']);
addJoins($scope.fieldsAndJoinsAndFunctionsAndWildcards, true, ['name', 'label']);
}
+ // Custom fields are supported if HAVING is
+ if (actionInfo.params.having) {
+ $scope.fieldsAndJoinsAndFunctionsAndWildcards.unshift({id: 'custom.*', text: 'custom.*', 'description': 'All custom fields'});
+ }
$scope.fieldsAndJoinsAndFunctionsAndWildcards.unshift({id: '*', text: '*', 'description': 'All core ' + $scope.entity + ' fields'});
};
}, true);
}
if (name === 'select' && actionInfo.params.having) {
- $scope.$watchCollection('params.select', function(values) {
+ $scope.$watchCollection('params.select', function(newSelect) {
+ // Ignore row_count, it can't be used in HAVING clause
+ var select = _.without(newSelect, 'row_count');
$scope.havingOptions.length = 0;
- _.each(values, function(item) {
- var pieces = item.split(' AS '),
+ // An empty select is an implicit *
+ if (!select.length) {
+ select.push('*');
+ }
+ _.each(select, function(item) {
+ var joinEntity,
+ pieces = item.split(' AS '),
alias = _.trim(pieces[pieces.length - 1]).replace(':label', ':name');
- $scope.havingOptions.push({id: alias, text: alias});
+ // Expand wildcards
+ if (alias[alias.length - 1] === '*') {
+ if (alias.length > 1) {
+ joinEntity = entityNameFromAlias(alias.slice(0, -2));
+ }
+ var fieldList = _.filter(getEntity(joinEntity).fields, {custom_field_id: null});
+ formatForSelect2(fieldList, $scope.havingOptions, 'name', ['description', 'required', 'default_value'], alias.slice(0, -1));
+ }
+ else {
+ $scope.havingOptions.push({id: alias, text: alias});
+ }
});
});
}
break;
case 'cli':
- // Write cli code
- code.cv = 'cv api4 ' + entity + '.' + action + " '" + stringify(params) + "'";
+ // Cli code using json input
+ code.long = 'cv api4 ' + entity + '.' + action + ' ' + cliFormat(JSON.stringify(params));
+ code.pipe = 'echo ' + cliFormat(JSON.stringify(params)) + ' | cv api4 ' + entity + '.' + action + ' --in=json';
+
+ // Cli code using short syntax
+ code.short = 'cv api4 ' + entity + '.' + action;
+ var limitSet = false;
+ _.each(params, function(param, key) {
+ switch (true) {
+ case (key === 'select' && !_.includes(param.join(), ' ')):
+ code.short += ' +s ' + cliFormat(param.join(','));
+ break;
+ case (key === 'where' && !_.intersection(_.map(param, 0), ['AND', 'OR', 'NOT']).length):
+ _.each(param, function(clause) {
+ code.short += ' +w ' + cliFormat(clause[0] + ' ' + clause[1] + (clause.length > 2 ? (' ' + JSON.stringify(clause[2])) : ''));
+ });
+ break;
+ case (key === 'orderBy'):
+ _.each(param, function(dir, field) {
+ code.short += ' +o ' + cliFormat(field + ' ' + dir);
+ });
+ break;
+ case (key === 'values'):
+ _.each(param, function(val, field) {
+ code.short += ' +v ' + cliFormat(field + '=' + val);
+ });
+ break;
+ case (key === 'limit' || key === 'offset'):
+ // These 2 get combined
+ if (!limitSet) {
+ limitSet = true;
+ code.short += ' +l ' + (params.limit || '0') + (params.offset ? ('@' + params.offset) : '');
+ }
+ break;
+ default:
+ code.short += ' ' + key + '=' + (typeof param === 'string' ? cliFormat(param) : cliFormat(JSON.stringify(param)));
+ }
+ });
}
}
_.each($scope.code, function(vals) {
// Format oop params
function formatOOP(entity, action, params, indent) {
var code = '',
- newLine = "\n" + _.repeat(' ', indent);
+ newLine = "\n" + _.repeat(' ', indent),
+ perm = params.checkPermissions === false ? 'FALSE' : '';
if (entity.substr(0, 7) !== 'Custom_') {
- code = "\\Civi\\Api4\\" + entity + '::' + action + '()';
+ code = "\\Civi\\Api4\\" + entity + '::' + action + '(' + perm + ')';
} else {
- code = "\\Civi\\Api4\\CustomValue::" + action + "('" + entity.substr(7) + "')";
+ code = "\\Civi\\Api4\\CustomValue::" + action + "('" + entity.substr(7) + "'" + (perm ? ', ' : '') + perm + ")";
}
_.each(params, function(param, key) {
var val = '';
code += (chain.length > 3 ? ',' : '') + (!_.isEmpty(chain[2]) ? newLine : ' ') + (chain.length > 3 ? phpFormat(chain[3]) : '') + ')';
});
}
- else {
+ else if (key !== 'checkPermissions') {
code += newLine + "->set" + ucfirst(key) + '(' + phpFormat(param, 2 + indent) + ')';
}
});
$scope.debug = debugFormat(resp.data);
$scope.result = [
formatMeta(resp.data),
- prettyPrintOne('(' + resp.data.values.length + ') ' + _.escape(JSON.stringify(resp.data.values, null, 2)), 'js', 1)
+ prettyPrintOne((_.isArray(resp.data.values) ? '(' + resp.data.values.length + ') ' : '') + _.escape(JSON.stringify(resp.data.values, null, 2)), 'js', 1)
];
}, function(resp) {
$scope.loading = false;
return JSON.stringify(val).replace(/\$/g, '\\$');
}
+ // Format string to be cli-input-safe
+ function cliFormat(str) {
+ if (!_.includes(str, ' ') && !_.includes(str, '"') && !_.includes(str, "'")) {
+ return str;
+ }
+ if (!_.includes(str, "'")) {
+ return "'" + str + "'";
+ }
+ if (!_.includes(str, '"')) {
+ return '"' + str + '"';
+ }
+ return "'" + str.replace(/'/g, "\\'") + "'";
+ }
+
function fetchMeta() {
crmApi4(getMetaParams)
.then(function(data) {