APIv4 - Fix autocomplete for Individual,Household,Organization entities
authorcolemanw <coleman@civicrm.org>
Tue, 3 Oct 2023 23:22:39 +0000 (19:22 -0400)
committercolemanw <coleman@civicrm.org>
Tue, 3 Oct 2023 23:57:54 +0000 (19:57 -0400)
CRM/Core/DAO/AllCoreTables.php
Civi/Api4/Service/Schema/SchemaMapBuilder.php
tests/phpunit/api/v4/Custom/CustomEntityReferenceTest.php

index 4c22ee769bc13520eea1fef2141d07eebb525fed..ba28171ba925390e65ea2e5c4b39d13ef8f4cf09 100644 (file)
@@ -358,7 +358,7 @@ class CRM_Core_DAO_AllCoreTables {
    *
    * @param string $briefName
    *
-   * @return FALSE|string
+   * @return string
    */
   public static function getTableForEntityName($briefName): string {
     self::init();
index dc388ae4e80e4f0b6127f6746db1f77449b8eaa9..576b96ec6e05736de16cef5b23482d130c5301a6 100644 (file)
@@ -16,6 +16,7 @@ use Civi\Api4\Entity;
 use Civi\Api4\Event\SchemaMapBuildEvent;
 use Civi\Api4\Service\Schema\Joinable\CustomGroupJoinable;
 use Civi\Api4\Service\Schema\Joinable\Joinable;
+use Civi\Api4\Utils\CoreUtil;
 use Civi\Core\Service\AutoService;
 use Civi\Core\CiviEventDispatcherInterface;
 use CRM_Core_DAO_AllCoreTables as AllCoreTables;
@@ -142,7 +143,7 @@ class SchemaMapBuilder extends AutoService {
       }
 
       if ($fieldData->data_type === 'EntityReference' && isset($fieldData->fk_entity)) {
-        $targetTable = AllCoreTables::getTableForEntityName($fieldData->fk_entity);
+        $targetTable = self::getTableName($fieldData->fk_entity);
         $joinable = new Joinable($targetTable, 'id', $fieldData->name);
         $customTable->addTableLink($fieldData->column_name, $joinable);
       }
@@ -162,4 +163,15 @@ class SchemaMapBuilder extends AutoService {
     }
   }
 
+  /**
+   * @param string $entityName
+   * @return string
+   */
+  private static function getTableName(string $entityName) {
+    if (CoreUtil::isContact($entityName)) {
+      return 'civicrm_contact';
+    }
+    return AllCoreTables::getTableForEntityName($entityName);
+  }
+
 }
index 3f34c1c0cc8e6a60afae90ec66776b67c5b2e568..be9594b93139f50853fc4236efc049a593426151 100644 (file)
@@ -21,6 +21,8 @@ use Civi\Api4\Activity;
 use Civi\Api4\Contact;
 use Civi\Api4\CustomGroup;
 use Civi\Api4\CustomField;
+use Civi\Api4\Individual;
+use Civi\Api4\Organization;
 
 /**
  * @group headless
@@ -44,6 +46,11 @@ class CustomEntityReferenceTest extends CustomTestBase {
       'fk_entity' => 'Activity',
       'filter' => "subject=$subject",
     ])->execute()->single();
+    // Spec should only exist for Individuals
+    $spec = Organization::getFields(FALSE)
+      ->addWhere('name', '=', 'EntityRefFields.TestActivityReference')
+      ->execute()->first();
+    $this->assertNull($spec);
     // Check metadata
     $spec = Contact::getFields(FALSE)
       ->addWhere('name', '=', 'EntityRefFields.TestActivityReference')
@@ -71,4 +78,58 @@ class CustomEntityReferenceTest extends CustomTestBase {
     $this->assertGreaterThan(2, $result->countFetched());
   }
 
+  /**
+   * Ensure custom fields of type EntityReference correctly apply filters
+   */
+  public function testEntityReferenceCustomFieldByContactType(): void {
+    CustomGroup::create()->setValues([
+      'title' => 'EntityRefFields',
+      'extends' => 'Individual',
+    ])->execute();
+    CustomField::create()->setValues([
+      'label' => 'TestOrgRef',
+      'custom_group_id.name' => 'EntityRefFields',
+      'html_type' => 'Autocomplete-Select',
+      'data_type' => 'EntityReference',
+      'fk_entity' => 'Organization',
+    ])->execute()->single();
+    // Check metadata
+    $spec = Individual::getFields(FALSE)
+      ->addWhere('name', '=', 'EntityRefFields.TestOrgRef')
+      ->execute()->single();
+    $this->assertNull($spec['suffixes']);
+    $this->assertEquals('EntityRef', $spec['input_type']);
+    $this->assertEquals('Organization', $spec['fk_entity']);
+    // Check results
+    $contacts = $this->saveTestRecords('Contact', [
+      'records' => [
+        ['contact_type' => 'Organization'],
+        ['contact_type' => 'Individual'],
+        ['contact_type' => 'Household'],
+      ],
+    ])->indexBy('contact_type')->column('id');
+    // Autocomplete by id
+    $result = (array) Organization::autocomplete(FALSE)
+      ->setFieldName("Contact.EntityRefFields.TestOrgRef")
+      ->setInput((string) $contacts['Organization'])
+      ->execute();
+    $this->assertCount(1, $result);
+    // Autocomplete by id
+    $result = (array) Organization::autocomplete(FALSE)
+      ->setFieldName("Contact.EntityRefFields.TestOrgRef")
+      ->setInput((string) $contacts['Individual'])
+      ->execute();
+    $this->assertCount(0, $result);
+    // Autocomplete by id
+    $result = (array) Organization::autocomplete(FALSE)
+      ->setFieldName("Contact.EntityRefFields.TestOrgRef")
+      ->setInput((string) $contacts['Household'])
+      ->execute();
+    $this->assertCount(0, $result);
+    // No field specified
+    $result = Contact::autocomplete(FALSE)
+      ->execute();
+    $this->assertGreaterThan(2, $result->countFetched());
+  }
+
 }