Because the RelationshipCache entity is meant to be used without requiring a join to the Relationship table,
this permits direct access to Relationship custom fields as if they belong to the RelationshipCache table.
'Address' => ts('Addresses'),
'Campaign' => ts('Campaigns'),
];
- $contactTypes = self::contactType();
- $contactTypes = !empty($contactTypes) ? ['Contact' => 'Contacts'] + $contactTypes : [];
+ $contactTypes = ['Contact' => ts('Contacts')] + self::contactType();
$extendObjs = CRM_Core_OptionGroup::values('cg_extend_objects');
$customGroupExtends = array_merge($contactTypes, $customGroupExtends, $extendObjs);
return $customGroupExtends;
/**
* @param \Civi\Api4\Service\Schema\SchemaMap $map
* @param \Civi\Api4\Service\Schema\Table $baseTable
- * @param string $entity
+ * @param string $entityName
*/
- private function addCustomFields(SchemaMap $map, Table $baseTable, $entity) {
+ private function addCustomFields(SchemaMap $map, Table $baseTable, string $entityName) {
+ $customInfo = \Civi\Api4\Utils\CoreUtil::getCustomGroupExtends($entityName);
// Don't be silly
- if (!array_key_exists($entity, \CRM_Core_SelectValues::customGroupExtends())) {
+ if (!$customInfo) {
return;
}
- $queryEntity = (array) $entity;
- if ($entity == 'Contact') {
- $queryEntity = ['Contact', 'Individual', 'Organization', 'Household'];
- }
$fieldData = \CRM_Utils_SQL_Select::from('civicrm_custom_field f')
->join('custom_group', 'INNER JOIN civicrm_custom_group g ON g.id = f.custom_group_id')
->select(['g.name as custom_group_name', 'g.table_name', 'g.is_multiple', 'f.name', 'label', 'column_name', 'option_group_id'])
- ->where('g.extends IN (@entity)', ['@entity' => $queryEntity])
+ ->where('g.extends IN (@entity)', ['@entity' => $customInfo['extends']])
->where('g.is_active')
->where('f.is_active')
->execute();
// Add backreference
if (!empty($fieldData->is_multiple)) {
- $joinable = new Joinable($baseTable->getName(), 'id', AllCoreTables::convertEntityNameToLower($entity));
+ $joinable = new Joinable($baseTable->getName(), $customInfo['column'], AllCoreTables::convertEntityNameToLower($entityName));
$customTable->addTableLink('entity_id', $joinable);
}
}
foreach ($links as $alias => $link) {
$joinable = new CustomGroupJoinable($link['tableName'], $alias, $link['isMultiple'], $link['columns']);
- $baseTable->addTableLink('id', $joinable);
+ $baseTable->addTableLink($customInfo['column'], $joinable);
}
}
// Real entities
if (strpos($entity, 'Custom_') !== 0) {
$this->addDAOFields($entity, $action, $specification, $values);
- if ($includeCustom && array_key_exists($entity, \CRM_Core_SelectValues::customGroupExtends())) {
+ if ($includeCustom) {
$this->addCustomFields($entity, $specification, $values);
}
}
* @throws \API_Exception
*/
private function addCustomFields($entity, RequestSpec $specification, $values = []) {
- // Custom_group.extends pretty much maps 1-1 with entity names, except for a couple oddballs (Contact, Participant).
- $extends = [$entity];
- if ($entity === 'Contact') {
- $contactType = !empty($values['contact_type']) ? [$values['contact_type']] : \CRM_Contact_BAO_ContactType::basicTypes();
- $extends = array_merge(['Contact'], $contactType);
+ $customInfo = \Civi\Api4\Utils\CoreUtil::getCustomGroupExtends($entity);
+ if (!$customInfo) {
+ return;
}
- if ($entity === 'Participant') {
- $extends = ['Participant', 'ParticipantRole', 'ParticipantEventName', 'ParticipantEventType'];
+ // If a contact_type was passed in, exclude custom groups for other contact types
+ if ($entity === 'Contact' && !empty($values['contact_type'])) {
+ $extends = ['Contact', $values['contact_type']];
+ }
+ else {
+ $extends = $customInfo['extends'];
}
$customFields = CustomField::get(FALSE)
->addWhere('custom_group.extends', 'IN', $extends)
return $operators;
}
+ /**
+ * For a given API Entity, return the types of custom fields it supports and the column they join to.
+ *
+ * @param string $entityName
+ * @return array|mixed|null
+ * @throws \API_Exception
+ * @throws \Civi\API\Exception\UnauthorizedException
+ */
+ public static function getCustomGroupExtends(string $entityName) {
+ // Custom_group.extends pretty much maps 1-1 with entity names, except for a couple oddballs (Contact, Participant).
+ switch ($entityName) {
+ case 'Contact':
+ return [
+ 'extends' => array_merge(['Contact'], array_keys(\CRM_Core_SelectValues::contactType())),
+ 'column' => 'id',
+ ];
+
+ case 'Participant':
+ return [
+ 'extends' => ['Participant', 'ParticipantRole', 'ParticipantEventName', 'ParticipantEventType'],
+ 'column' => 'id',
+ ];
+
+ case 'RelationshipCache':
+ return [
+ 'extends' => ['Relationship'],
+ 'column' => 'relationship_id',
+ ];
+ }
+ if (array_key_exists($entityName, \CRM_Core_SelectValues::customGroupExtends())) {
+ return [
+ 'extends' => [$entityName],
+ 'column' => 'id',
+ ];
+ }
+ return NULL;
+ }
+
}
use Civi\Api4\Contact;
use Civi\Api4\CustomField;
use Civi\Api4\CustomGroup;
+use Civi\Api4\Relationship;
+use Civi\Api4\RelationshipCache;
/**
* @group headless
$this->assertNotContains($contactId2, array_keys((array) $search));
}
+ public function testRelationshipCacheCustomFields() {
+ $cgName = uniqid('RelFields');
+
+ $customGroup = CustomGroup::create(FALSE)
+ ->addValue('name', $cgName)
+ ->addValue('extends', 'Relationship')
+ ->execute()
+ ->first();
+
+ CustomField::create(FALSE)
+ ->addValue('label', 'PetName')
+ ->addValue('custom_group_id', $customGroup['id'])
+ ->addValue('html_type', 'Text')
+ ->addValue('data_type', 'String')
+ ->execute();
+
+ $parent = Contact::create(FALSE)
+ ->addValue('first_name', 'Parent')
+ ->addValue('last_name', 'Tester')
+ ->addValue('contact_type', 'Individual')
+ ->execute()
+ ->first()['id'];
+
+ $child = Contact::create(FALSE)
+ ->addValue('first_name', 'Child')
+ ->addValue('last_name', 'Tester')
+ ->addValue('contact_type', 'Individual')
+ ->execute()
+ ->first()['id'];
+
+ $relationship = Relationship::create(FALSE)
+ ->addValue('contact_id_a', $parent)
+ ->addValue('contact_id_b', $child)
+ ->addValue('relationship_type_id', 1)
+ ->addValue("$cgName.PetName", 'Buddy')
+ ->execute();
+
+ $results = RelationshipCache::get(FALSE)
+ ->addSelect("$cgName.PetName")
+ ->addWhere("$cgName.PetName", '=', 'Buddy')
+ ->execute();
+
+ $this->assertCount(2, $results);
+ $this->assertEquals('Buddy', $results[0]["$cgName.PetName"]);
+ }
+
}