$options = CRM_Core_PseudoConstant::get(__CLASS__, $fieldName, $params, $context);
+ // Special formatting for validate/match context
+ if ($fieldName == 'entity_table' && in_array($context, array('validate', 'match'))) {
+ $options = array();
+ foreach (self::buildOptions($fieldName) as $tableName => $label) {
+ $bao = CRM_Core_DAO_AllCoreTables::getClassForTable($tableName);
+ $apiName = CRM_Core_DAO_AllCoreTables::getBriefName($bao);
+ $options[$tableName] = $apiName;
+ }
+ }
+
return $options;
}
* @return array
*/
public static function entityTables() {
- $tables = array(
- 'civicrm_relationship',
- 'civicrm_contact',
- 'civicrm_participant',
- 'civicrm_contribution',
+ return array(
+ 'civicrm_relationship' => 'Relationship',
+ 'civicrm_contact' => 'Contact',
+ 'civicrm_participant' => 'Participant',
+ 'civicrm_contribution' => 'Contribution',
);
- // Identical keys & values
- return array_combine($tables, $tables);
}
}
* @return array
*/
public static function entityTables() {
- $tables = array(
- 'civicrm_event',
- 'civicrm_contribution_page',
- 'civicrm_survey',
+ return array(
+ 'civicrm_event' => 'Event',
+ 'civicrm_contribution_page' => 'ContributionPage',
+ 'civicrm_survey' => 'Survey',
);
- // Identical keys & values
- return array_combine($tables, $tables);
}
}
// if callback is specified..
if (!empty($pseudoconstant['callback'])) {
- $fieldOptions = call_user_func(Civi\Core\Resolver::singleton()->get($pseudoconstant['callback']));
+ $fieldOptions = call_user_func(Civi\Core\Resolver::singleton()->get($pseudoconstant['callback']), $context);
//CRM-18223: Allow additions to field options via hook.
CRM_Utils_Hook::fieldOptions($entity, $fieldName, $fieldOptions, $params);
return $fieldOptions;
* Whitelist of possible values for the entity_table field
* @return array
*/
- public static function mailingGroupEntityTables() {
- $tables = array(
- CRM_Contact_BAO_Group::getTableName(),
- CRM_Mailing_BAO_Mailing::getTableName(),
+ public static function mailingGroupEntityTables($context = NULL) {
+ return array(
+ CRM_Contact_BAO_Group::getTableName() => 'Group',
+ CRM_Mailing_BAO_Mailing::getTableName() => 'Mailing',
);
- // Identical keys & values
- return array_combine($tables, $tables);
}
/**
if ($depth > self::MAX_JOINS) {
throw new UnauthorizedException("Maximum number of joins exceeded in parameter $fkFieldName");
}
+ $subStack = array_slice($stack, 0, $depth);
+ $this->getJoinInfo($fkField, $subStack);
if (!isset($fkField['FKApiName']) || !isset($fkField['FKClassName'])) {
// Join doesn't exist - might be another param with a dot in it for some reason, we'll just ignore it.
return NULL;
}
- $subStack = array_slice($stack, 0, $depth);
// Ensure we have permission to access the other api
if (!$this->checkPermissionToJoin($fkField['FKApiName'], $subStack)) {
throw new UnauthorizedException("Authorization failed to join onto {$fkField['FKApiName']} api in parameter $fkFieldName");
return array($tableAlias, $fieldName);
}
+ /**
+ * Get join info for dynamically-joined fields (e.g. "entity_id")
+ *
+ * @param $fkField
+ * @param $stack
+ */
+ protected function getJoinInfo(&$fkField, $stack) {
+ if ($fkField['name'] == 'entity_id') {
+ $entityTableParam = substr(implode('.', $stack), 0, -2) . 'table';
+ $entityTable = \CRM_Utils_Array::value($entityTableParam, $this->where);
+ if ($entityTable && is_string($entityTable) && \CRM_Core_DAO_AllCoreTables::getClassForTable($entityTable)) {
+ $fkField['FKClassName'] = \CRM_Core_DAO_AllCoreTables::getClassForTable($entityTable);
+ $fkField['FKApiName'] = \CRM_Core_DAO_AllCoreTables::getBriefName($fkField['FKClassName']);
+ }
+ }
+ }
+
/**
* Joins onto a custom field
*
* @returns {*}
*/
function getField(name) {
- if (!name) {
- return {};
- }
- if (getFieldData[name]) {
- return getFieldData[name];
- }
- var ent = entity,
- act = action,
- prefix = '';
- _.each(name.split('.'), function(piece) {
- if (joins[prefix]) {
- ent = joins[prefix];
- act = 'get';
+ var field = {};
+ if (name && getFieldData[name]) {
+ field = _.cloneDeep(getFieldData[name]);
+ } else if (name) {
+ var ent = entity,
+ act = action,
+ prefix = '';
+ _.each(name.split('.'), function(piece) {
+ if (joins[prefix]) {
+ ent = joins[prefix];
+ act = 'get';
+ }
+ name = piece;
+ prefix += (prefix.length ? '.' : '') + piece;
+ });
+ if (getFieldsCache[ent+act].values[name]) {
+ field = _.cloneDeep(getFieldsCache[ent+act].values[name]);
}
- name = piece;
- prefix += (prefix.length ? '.' : '') + piece;
- });
- return getFieldsCache[ent+act].values[name] || {};
+ }
+ addJoinInfo(field, name);
+ return field;
+ }
+
+ function addJoinInfo(field, name) {
+ if (field.name === 'entity_id') {
+ var entityTableParam = name.slice(0, -2) + 'table';
+ if (params[entityTableParam]) {
+ field.FKApiName = getField(entityTableParam).options[params[entityTableParam]];
+ }
+ }
}
/**
});
}
+ function changeFKEntity() {
+ var $row = $(this).closest('tr'),
+ name = $('input.api-param-name', $row).val(),
+ operator = $('.api-param-op', $row).val();
+ if (name && name.slice(-12) === 'entity_table') {
+ $('input[value=' + name.slice(0, -5) + 'id]', '#api-join').prop('checked', false).change();
+ }
+ }
+
/**
* For "get" actions show the "return" options
*
if (operator !== '=') {
return false;
}
- return true;
+ return fieldName !== 'entity_table';
/*
* Attempt to resolve the ambiguity of the = operator using metadata
* commented out because there is not enough metadata in the api at this time
var joinable = {};
(function recurse(fields, joinable, prefix, depth, entities) {
_.each(fields, function(field) {
+ var name = prefix + field.name;
+ addJoinInfo(field, name);
var entity = field.FKApiName;
- if (entity && field.FKClassName) {
- var name = prefix + field.name;
+ if (entity) {
joinable[name] = {
- title: field.title,
+ title: field.title + ' (' + field.FKApiName + ')',
entity: entity,
checked: !!joins[name]
};
joinable[name].children = {};
recurse(getFieldsCache[entity+'get'].values, joinable[name].children, name + '.', depth+1, entities.concat(entity));
}
+ } else if (field.name == 'entity_id' && fields.entity_table && fields.entity_table.options) {
+ joinable[name] = {
+ title: field.title + ' (' + ts('First select %1', {1: fields.entity_table.title}) + ')',
+ entity: '',
+ disabled: true
+ };
}
});
- })(getFieldData, joinable, '', 1, [entity]);
+ })(_.cloneDeep(getFieldData), joinable, '', 1, [entity]);
if (!_.isEmpty(joinable)) {
// Send joinTpl as a param so it can recursively call itself to render children
$('#api-join').show().children('div').html(joinTpl({joins: joinable, tpl: joinTpl}));
checkBookKeepingEntity(entity, action);
})
.on('change keyup', 'input.api-input, #api-params select', buildParams)
+ .on('change', '.api-param-name, .api-param-value, .api-param-op', changeFKEntity)
.on('submit', submit);
$('#api-params')
#api-join li.join-enabled > i {
opacity: 1;
}
+ #api-join li.join-not-available {
+ font-style: italic;
+ }
#api-generated-wraper,
#api-result {
overflow: auto;
{literal}
<ul class="fa-ul">
<% _.forEach(joins, function(join, name) { %>
- <li <% if(join.checked) { %>class="join-enabled"<% } %>>
+ <li <% if(join.checked) { %>class="join-enabled"<% } if(join.disabled) { %>class="join-not-available"<% }%>>
<i class="fa-li crm-i fa-reply fa-rotate-180"></i>
<label for="select-join-<%= name %>" class="api-checkbox-label">
- <input type="checkbox" id="select-join-<%= name %>" value="<%= name %>" data-entity="<%= join.entity %>" <% if(join.checked) { %>checked<% } %>/>
+ <input type="checkbox" id="select-join-<%= name %>" value="<%= name %>" data-entity="<%= join.entity %>" <% if(join.checked) { %>checked<% } if(join.disabled) { %>disabled<% } %>/>
<%- join.title %>
</label>
</li>
}
}
- /**
- * Delete note.
- *
- * @param array $params
- *
- * @return array|int
- */
- public function noteDelete($params) {
- return $this->callAPISuccess('Note', 'delete', $params);
- }
-
/**
* Create custom field with Option Values.
*
$this->useTransaction(TRUE);
$this->_individualID = $this->individualCreate();
- $this->_tag = $this->tagCreate();
+ $this->_tag = $this->tagCreate(array('name' => 'EntityTagTest'));
$this->_tagID = $this->_tag['id'];
$this->_householdID = $this->houseHoldCreate();
$this->_organizationID = $this->organizationCreate();
$this->assertEquals($result['not_removed'], 1);
}
+ public function testEntityTagJoin() {
+ $org = $this->callAPISuccess('Contact', 'create', array(
+ 'contact_type' => 'Organization',
+ 'organization_name' => 'Org123',
+ 'api.EntityTag.create' => array(
+ 'tag_id' => $this->_tagID,
+ ),
+ ));
+ // Fetch contact info via join
+ $result = $this->callAPISuccessGetSingle('EntityTag', array(
+ 'return' => array("entity_id.organization_name", "tag_id.name"),
+ 'entity_id' => $org['id'],
+ 'entity_table' => "civicrm_contact",
+ ));
+ $this->assertEquals('Org123', $result['entity_id.organization_name']);
+ $this->assertEquals('EntityTagTest', $result['tag_id.name']);
+ // This should return no results by restricting contact_type
+ $result = $this->callAPISuccess('EntityTag', 'get', array(
+ 'return' => array("entity_id.organization_name"),
+ 'entity_id' => $org['id'],
+ 'entity_table' => "civicrm_contact",
+ 'entity_id.contact_type' => "Individual",
+ ));
+ $this->assertEquals(0, $result['count']);
+ }
+
}
$this->assertEquals(date('Y-m-d', strtotime($this->_params['modified_date'])), date('Y-m-d', strtotime($result['values'][$result['id']]['modified_date'])));
$this->assertArrayHasKey('id', $result);
- $note = array(
- 'id' => $result['id'],
- );
- $this->noteDelete($note);
}
public function testCreateWithApostropheInString() {
$this->assertEquals($result['values'][0]['note'], "Hello!!! ' testing Note");
$this->assertEquals($result['values'][0]['subject'], "With a '");
$this->assertArrayHasKey('id', $result);
-
- //CleanUP
- $note = array(
- 'id' => $result['id'],
- );
- $this->noteDelete($note);
}
/**
$apiResult = $this->callAPISuccess('note', 'create', $this->_params);
$this->assertAPISuccess($apiResult);
$this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($apiResult['values'][$apiResult['id']]['modified_date'])));
- $this->noteDelete(array(
- 'id' => $apiResult['id'],
- ));
}
/**
$this->callAPIAndDocument('note', 'delete', $params, __FUNCTION__, __FILE__);
}
+ public function testNoteJoin() {
+ $org = $this->callAPISuccess('Contact', 'create', array(
+ 'contact_type' => 'Organization',
+ 'organization_name' => 'Org123',
+ 'api.Note.create' => array(
+ 'note' => 'Hello join',
+ ),
+ ));
+ // Fetch contact info via join
+ $result = $this->callAPISuccessGetSingle('Note', array(
+ 'return' => array("entity_id.organization_name", "note"),
+ 'entity_id' => $org['id'],
+ 'entity_table' => "civicrm_contact",
+ ));
+ $this->assertEquals('Org123', $result['entity_id.organization_name']);
+ $this->assertEquals('Hello join', $result['note']);
+ // This should return no results by restricting contact_type
+ $result = $this->callAPISuccess('Note', 'get', array(
+ 'return' => array("entity_id.organization_name"),
+ 'entity_id' => $org['id'],
+ 'entity_table' => "civicrm_contact",
+ 'entity_id.contact_type' => "Individual",
+ ));
+ $this->assertEquals(0, $result['count']);
+ }
+
}
/**