From 85259d6f217d2b35829aa193f0053b2b216f4ccd Mon Sep 17 00:00:00 2001 From: colemanw Date: Thu, 16 Nov 2023 19:13:00 -0500 Subject: [PATCH] APIv4 - Fix multi-record custom entities FK join on entity_id This join was named contact instead of entity_id. Joins that don't match the field name are deprecated in APIv4 so the old join has been marked as such. Renaming the join fixes SearchKit ability to join from a custom entity to the parent record. --- Civi/Api4/Action/Entity/GetLinks.php | 2 +- Civi/Api4/Query/Api4SelectQuery.php | 4 ++-- Civi/Api4/Service/Schema/Joinable/Joinable.php | 13 ++++++------- Civi/Api4/Service/Schema/SchemaMapBuilder.php | 15 +++++++++------ tests/phpunit/api/v3/ACLPermissionTest.php | 4 ++-- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Civi/Api4/Action/Entity/GetLinks.php b/Civi/Api4/Action/Entity/GetLinks.php index 3408fea35b..e05d66de1e 100644 --- a/Civi/Api4/Action/Entity/GetLinks.php +++ b/Civi/Api4/Action/Entity/GetLinks.php @@ -36,7 +36,7 @@ class GetLinks extends \Civi\Api4\Generic\BasicGetAction { 'links' => [], ]; foreach ($table->getTableLinks() as $link) { - if (!$link->isDeprecated()) { + if (!$link->isDeprecatedBy()) { $item['links'][] = $link->toArray(); } } diff --git a/Civi/Api4/Query/Api4SelectQuery.php b/Civi/Api4/Query/Api4SelectQuery.php index 8887bc1834..d6681de88d 100644 --- a/Civi/Api4/Query/Api4SelectQuery.php +++ b/Civi/Api4/Query/Api4SelectQuery.php @@ -833,9 +833,9 @@ class Api4SelectQuery extends Api4Query { return; } } - if ($link->isDeprecated()) { + if ($link->isDeprecatedBy()) { $deprecatedAlias = $link->getAlias(); - \CRM_Core_Error::deprecatedWarning("Deprecated join alias '$deprecatedAlias' used in APIv4 get. Should be changed to '{$deprecatedAlias}_id'"); + \CRM_Core_Error::deprecatedWarning("Deprecated join alias '$deprecatedAlias' used in APIv4 {$this->getEntity()} join to $joinEntity. Should be changed to '{$link->isDeprecatedBy()}'."); } $virtualField = $link->getSerialize(); $baseTableAlias = $joinTreeNode['#table_alias']; diff --git a/Civi/Api4/Service/Schema/Joinable/Joinable.php b/Civi/Api4/Service/Schema/Joinable/Joinable.php index 80ed04b6e8..5005e43384 100644 --- a/Civi/Api4/Service/Schema/Joinable/Joinable.php +++ b/Civi/Api4/Service/Schema/Joinable/Joinable.php @@ -78,7 +78,7 @@ class Joinable { /** * @var bool */ - protected $deprecated = FALSE; + protected $deprecatedBy = FALSE; /** * @param $targetTable @@ -282,17 +282,16 @@ class Joinable { /** * @return bool */ - public function isDeprecated() { - return $this->deprecated; + public function isDeprecatedBy() { + return $this->deprecatedBy; } /** - * @param bool $deprecated - * + * @param string|null $deprecatedBy * @return $this */ - public function setDeprecated(bool $deprecated = TRUE) { - $this->deprecated = $deprecated; + public function setDeprecatedBy(string $deprecatedBy = NULL) { + $this->deprecatedBy = $deprecatedBy ?? $this->alias . '_id'; return $this; } diff --git a/Civi/Api4/Service/Schema/SchemaMapBuilder.php b/Civi/Api4/Service/Schema/SchemaMapBuilder.php index beb5862c6b..49a1c2642a 100644 --- a/Civi/Api4/Service/Schema/SchemaMapBuilder.php +++ b/Civi/Api4/Service/Schema/SchemaMapBuilder.php @@ -127,6 +127,15 @@ class SchemaMapBuilder extends AutoService { $customTable = $map->getTableByName($tableName); if (!$customTable) { $customTable = new Table($tableName); + // Add entity_id join from multi-record custom group to the + if (!empty($fieldData->is_multiple)) { + $newJoin = new Joinable($baseTable->getName(), $customInfo['column'], 'entity_id'); + $customTable->addTableLink('entity_id', $newJoin); + // Deprecated "contact" join name + $oldJoin = new Joinable($baseTable->getName(), $customInfo['column'], AllCoreTables::convertEntityNameToLower($entityName)); + $oldJoin->setDeprecatedBy('entity_id'); + $customTable->addTableLink('entity_id', $oldJoin); + } } $map->addTable($customTable); @@ -136,12 +145,6 @@ class SchemaMapBuilder extends AutoService { $links[$alias]['isMultiple'] = !empty($fieldData->is_multiple); $links[$alias]['columns'][$fieldData->name] = $fieldData->column_name; - // Add backreference - if (!empty($fieldData->is_multiple)) { - $joinable = new Joinable($baseTable->getName(), $customInfo['column'], AllCoreTables::convertEntityNameToLower($entityName)); - $customTable->addTableLink('entity_id', $joinable); - } - if ($fieldData->data_type === 'EntityReference' && isset($fieldData->fk_entity)) { $targetTable = self::getTableName($fieldData->fk_entity); $joinable = new Joinable($targetTable, 'id', $fieldData->name); diff --git a/tests/phpunit/api/v3/ACLPermissionTest.php b/tests/phpunit/api/v3/ACLPermissionTest.php index 9836950b54..9d75c2fded 100644 --- a/tests/phpunit/api/v3/ACLPermissionTest.php +++ b/tests/phpunit/api/v3/ACLPermissionTest.php @@ -1154,10 +1154,10 @@ class api_v3_ACLPermissionTest extends CiviUnitTestCase { $this->hookClass->setHook('civicrm_aclWhereClause', [$this, 'aclWhereOnlyOne']); $this->cleanupCachedPermissions(); - $customValues = CustomValue::get($group)->addSelect('*', 'contact.first_name')->execute(); + $customValues = CustomValue::get($group)->addSelect('*', 'entity_id.first_name')->execute(); $this->assertCount(1, $customValues); $this->assertEquals($c2, $customValues[0]['entity_id']); - $this->assertEquals('C2', $customValues[0]['contact.first_name']); + $this->assertEquals('C2', $customValues[0]['entity_id.first_name']); $customValues = Contact::get() ->addJoin('Custom_' . $group . ' AS cf') -- 2.25.1