APIv4 - Add fk_column to getFields metadata
authorcolemanw <coleman@civicrm.org>
Wed, 3 Jan 2024 14:15:00 +0000 (09:15 -0500)
committercolemanw <coleman@civicrm.org>
Thu, 4 Jan 2024 01:26:00 +0000 (20:26 -0500)
Before: getFields contained incomplete info about foreign keys, so trying to map the schema was unnecessarily difficult.

After: No need to use extra DAO methods like getReferenceColumns() to find out about FKs. All the info is returned by getFields.

Civi/Api4/Generic/DAOGetFieldsAction.php
Civi/Api4/Service/Spec/SpecFormatter.php
Civi/Schema/Traits/DataTypeSpecTrait.php
tests/phpunit/api/v4/Action/GetFieldsTest.php
tests/phpunit/api/v4/Custom/CustomEntityReferenceTest.php

index 8b4a5655ffd2c09ba798ae603548dc5c68899017..251724dc339d939606fccc9562acefe3af200782 100644 (file)
@@ -130,6 +130,11 @@ class DAOGetFieldsAction extends BasicGetFieldsAction {
 
   public function fields() {
     $fields = parent::fields();
+    $fields[] = [
+      'name' => 'fk_column',
+      'data_type' => 'String',
+      'description' => 'Name of fk_entity column this field references.',
+    ];
     $fields[] = [
       'name' => 'dfk_entities',
       'description' => 'List of possible entity types this field could be referencing.',
index 47506d54aa5b87dae47f433ded52fbafa5f103e4..b13d1f4b9243d580c13e7d1597fad7aa181e4905 100644 (file)
@@ -117,6 +117,9 @@ class SpecFormatter {
     elseif (($data['html']['type'] ?? NULL) === 'EntityRef' && !empty($data['pseudoconstant']['table'])) {
       $field->setFkEntity(CoreUtil::getApiNameFromTableName($data['pseudoconstant']['table']));
     }
+    if (!empty($data['FKColumnName'])) {
+      $field->setFkColumn($data['FKColumnName']);
+    }
 
     return $field;
   }
index 1c4b9bef1c10830510d00183c6a8484dc7d30295..1ffe6c38814ff810eb0d97b5211a32b752a5bfce 100644 (file)
@@ -41,6 +41,11 @@ trait DataTypeSpecTrait {
    */
   public $fkEntity;
 
+  /**
+   * @var string
+   */
+  public $fkColumn;
+
   /**
    * @var string
    */
@@ -98,7 +103,27 @@ trait DataTypeSpecTrait {
    */
   public function setFkEntity($fkEntity) {
     $this->fkEntity = $fkEntity;
+    // If the field has a FK Entity, then FK Column also must be set.
+    if ($fkEntity) {
+      // Ensure a sensible default if not already set.
+      $this->fkColumn ??= 'id';
+    }
+    return $this;
+  }
 
+  /**
+   * @return string|null
+   */
+  public function getFkColumn(): ?string {
+    return $this->fkColumn;
+  }
+
+  /**
+   * @param string $fkColumn
+   * @return $this
+   */
+  public function setFkColumn($fkColumn) {
+    $this->fkColumn = $fkColumn;
     return $this;
   }
 
index 8aeab52cc85f2853824ed20eb3b8082679181f92..587bf52b7ed849ec66da954ab9a81c3a876d3696 100644 (file)
@@ -253,6 +253,7 @@ class GetFieldsTest extends Api4TestBase implements TransactionalInterface {
     // fk_entity should be specific to specified entity_table, but dfk_entities should still contain all values
     $this->assertEquals('Activity', $tagFields['entity_id']['fk_entity']);
     $this->assertContains('Contact', $tagFields['entity_id']['dfk_entities']);
+    $this->assertEquals('id', $tagFields['entity_id']['fk_column']);
 
     $tagFields = EntityTag::getFields(FALSE)
       ->addValue('entity_table:name', 'Contact')
index be9594b93139f50853fc4236efc049a593426151..da05c6d4125cd5c5da57ab6ae1d265b80e279618 100644 (file)
@@ -58,6 +58,7 @@ class CustomEntityReferenceTest extends CustomTestBase {
     $this->assertNull($spec['suffixes']);
     $this->assertEquals('EntityRef', $spec['input_type']);
     $this->assertEquals('Activity', $spec['fk_entity']);
+    $this->assertEquals('id', $spec['fk_column']);
     $this->assertEquals($subject, $spec['input_attrs']['filter']['subject']);
     // Check results
     $activities = $this->saveTestRecords('Activity', [