From 92d411be342eb61620366b0395aa74a774b10d70 Mon Sep 17 00:00:00 2001 From: colemanw Date: Mon, 1 Jan 2024 23:24:16 -0500 Subject: [PATCH] DAO - Return reference columns based on field metadata This deletes getReferenceColumns() from the DAO boilerplate and adds all the necessary field metadata so that they can be generated by the parent class. --- CRM/Core/CodeGen/Specification.php | 9 +++++--- CRM/Core/DAO.php | 27 +++++++++++++++++++++--- tests/phpunit/CRM/Core/DAOTest.php | 27 ++++++++++++++++++++++++ xml/templates/dao.tpl | 33 ++++++------------------------ 4 files changed, 63 insertions(+), 33 deletions(-) diff --git a/CRM/Core/CodeGen/Specification.php b/CRM/Core/CodeGen/Specification.php index 493323264d..0d7a12ca5a 100644 --- a/CRM/Core/CodeGen/Specification.php +++ b/CRM/Core/CodeGen/Specification.php @@ -140,6 +140,7 @@ class CRM_Core_CodeGen_Specification { $tables[$name]['foreignKey'][$fkey]['className'] = $classNames[$ftable]; $tables[$name]['foreignKey'][$fkey]['fileName'] = str_replace('_', '/', $classNames[$ftable]) . '.php'; $tables[$name]['fields'][$fkey]['FKClassName'] = $classNames[$ftable]; + $tables[$name]['fields'][$fkey]['FKColumnName'] = $tables[$name]['foreignKey'][$fkey]['key']; } } @@ -296,8 +297,10 @@ class CRM_Core_CodeGen_Specification { $this->getDynamicForeignKey($foreignXML, $dynamicForeign, $name); } } - if (!empty($dynamicForeign)) { - $table['dynamicForeignKey'] = $dynamicForeign; + $table['dynamicForeignKey'] = $dynamicForeign; + foreach ($dynamicForeign as $dfk) { + $fields[$dfk['idColumn']]['FKColumnName'] = $dfk['key']; + $fields[$dfk['idColumn']]['DFKEntityColumn'] = $dfk['typeColumn']; } } @@ -737,7 +740,7 @@ class CRM_Core_CodeGen_Specification { $foreignKey = [ 'idColumn' => trim($foreignXML->idColumn), 'typeColumn' => trim($foreignXML->typeColumn), - 'key' => trim($this->value('key', $foreignXML) ?? ''), + 'key' => trim($this->value('key', $foreignXML) ?? 'id'), ]; $dynamicForeignKeys[] = $foreignKey; } diff --git a/CRM/Core/DAO.php b/CRM/Core/DAO.php index 7062e76140..98ac4c4c8a 100644 --- a/CRM/Core/DAO.php +++ b/CRM/Core/DAO.php @@ -539,8 +539,29 @@ class CRM_Core_DAO extends DB_DataObject { */ public static function getReferenceColumns() { if (!isset(Civi::$statics[static::class]['links'])) { - Civi::$statics[static::class]['links'] = static::createReferenceColumns(static::class); - CRM_Core_DAO_AllCoreTables::invoke(static::class, 'links_callback', Civi::$statics[static::class]['links']); + $links = static::createReferenceColumns(static::class); + // Add references based on field metadata + foreach (static::fields() as $field) { + if (!empty($field['FKClassName'])) { + $links[] = new CRM_Core_Reference_Basic( + static::getTableName(), + $field['name'], + CRM_Core_DAO_AllCoreTables::getTableForClass($field['FKClassName']), + $field['FKColumnName'] ?? 'id' + ); + } + if (!empty($field['DFKEntityColumn'])) { + $links[] = new CRM_Core_Reference_Dynamic( + static::getTableName(), + $field['name'], + NULL, + $field['FKColumnName'] ?? 'id', + $field['DFKEntityColumn'] + ); + } + } + CRM_Core_DAO_AllCoreTables::invoke(static::class, 'links_callback', $links); + Civi::$statics[static::class]['links'] = $links; } return Civi::$statics[static::class]['links']; } @@ -2528,7 +2549,7 @@ SELECT contact_id $className::getTableName(), $field['name'], 'civicrm_option_value', - CRM_Utils_Array::value('keyColumn', $field['pseudoconstant'], 'value'), + $field['pseudoconstant']['keyColumn'] ?? 'value', $field['pseudoconstant']['optionGroupName'] ); } diff --git a/tests/phpunit/CRM/Core/DAOTest.php b/tests/phpunit/CRM/Core/DAOTest.php index 5dbdcd8632..69ad66d93b 100644 --- a/tests/phpunit/CRM/Core/DAOTest.php +++ b/tests/phpunit/CRM/Core/DAOTest.php @@ -22,6 +22,33 @@ class CRM_Core_DAOTest extends CiviUnitTestCase { $this->assertInstanceOf(\CRM_Core_Reference_Basic::class, $contactRef); } + public function testGetDynamicReferenceColumns(): void { + // CRM_Core_DAO_EntityTag has an example of all 3 types of references + $referenceColumns = []; + foreach (CRM_Core_DAO_EntityTag::getReferenceColumns() as $reference) { + $this->assertEquals('civicrm_entity_tag', $reference->getReferenceTable()); + $referenceColumns[$reference->getReferenceKey()] = $reference; + } + + $reference = $referenceColumns['entity_table']; + $this->assertInstanceOf(\CRM_Core_Reference_OptionValue::class, $reference); + $this->assertNull($reference->getTypeColumn()); + $this->assertEquals('civicrm_option_value', $reference->getTargetTable()); + $this->assertEquals('value', $reference->getTargetKey()); + + $reference = $referenceColumns['tag_id']; + $this->assertInstanceOf(\CRM_Core_Reference_Basic::class, $reference); + $this->assertNull($reference->getTypeColumn()); + $this->assertEquals('civicrm_tag', $reference->getTargetTable()); + $this->assertEquals('id', $reference->getTargetKey()); + + $reference = $referenceColumns['entity_id']; + $this->assertInstanceOf(\CRM_Core_Reference_Dynamic::class, $reference); + $this->assertEquals('entity_table', $reference->getTypeColumn()); + $this->assertNull($reference->getTargetTable()); + $this->assertEquals('id', $reference->getTargetKey()); + } + public function testGetReferencesToTable(): void { $refs = CRM_Core_DAO::getReferencesToTable(CRM_Financial_DAO_FinancialType::getTableName()); $refsBySource = []; diff --git a/xml/templates/dao.tpl b/xml/templates/dao.tpl index 0432e69b67..f7d0e83d52 100644 --- a/xml/templates/dao.tpl +++ b/xml/templates/dao.tpl @@ -115,33 +115,6 @@ class {$table.className} extends CRM_Core_DAO {ldelim} {rdelim} {/if} - -{if !empty($table.foreignKey) || !empty($table.dynamicForeignKey)} - /** - * Returns foreign keys and entity references. - * - * @return array - * [CRM_Core_Reference_Interface] - */ - public static function getReferenceColumns() {ldelim} - if (!isset(Civi::$statics[__CLASS__]['links'])) {ldelim} - Civi::$statics[__CLASS__]['links'] = static::createReferenceColumns(__CLASS__); -{if isset($table.foreignKey)} -{foreach from=$table.foreignKey item=foreign} - Civi::$statics[__CLASS__]['links'][] = new CRM_Core_Reference_Basic(self::getTableName(), '{$foreign.name}', '{$foreign.table}', '{$foreign.key}'); -{/foreach} -{/if} -{if isset($table.dynamicForeignKey)} -{foreach from=$table.dynamicForeignKey item=foreign} - Civi::$statics[__CLASS__]['links'][] = new CRM_Core_Reference_Dynamic(self::getTableName(), '{$foreign.idColumn}', NULL, '{$foreign.key|default:'id'}', '{$foreign.typeColumn}'); -{/foreach} -{/if} - CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'links_callback', Civi::$statics[__CLASS__]['links']); - {rdelim} - return Civi::$statics[__CLASS__]['links']; - {rdelim} -{/if} {* table.foreignKey *} - /** * Returns all the column names of this table * @@ -219,6 +192,12 @@ class {$table.className} extends CRM_Core_DAO {ldelim} {if isset($field.FKClassName)} 'FKClassName' => '{$field.FKClassName}', {/if} +{if isset($field.DFKEntityColumn)} + 'DFKEntityColumn' => '{$field.DFKEntityColumn}', +{/if} +{if isset($field.FKColumnName)} + 'FKColumnName' => '{$field.FKColumnName}', +{/if} {if !empty($field.component)} 'component' => '{$field.component}', {/if} -- 2.25.1