AllCoreTables - Allow virtual entities to share a DAO class
authorColeman Watts <coleman@civicrm.org>
Mon, 18 Oct 2021 14:54:03 +0000 (10:54 -0400)
committerColeman Watts <coleman@civicrm.org>
Mon, 25 Oct 2021 12:06:01 +0000 (08:06 -0400)
Indexes entities by brief name instead of class name,
which allows one class to be shared by multiple entities.

CRM/Core/BAO/EntityTag.php
CRM/Core/DAO/AllCoreTables.php
Civi/Api4/Service/Schema/SchemaMapBuilder.php
tests/phpunit/CRM/Core/DAO/AllCoreTablesTest.php

index 580729a87c6f3c3fe3d566cebe6bca2c452245dd..daa8568faae9658277f4b511e68fd54b23ace127 100644 (file)
@@ -486,13 +486,13 @@ class CRM_Core_BAO_EntityTag extends CRM_Core_DAO_EntityTag {
     // This is probably fairly mild in terms of helping performance - a case could be made to check if tags
     // exist before deleting (further down) as delete is a locking action.
     $entity = CRM_Core_DAO_AllCoreTables::getBriefName(get_class($event->object));
-    if (!isset(Civi::$statics[__CLASS__]['tagged_entities'][$entity])) {
+    if ($entity && !isset(Civi::$statics[__CLASS__]['tagged_entities'][$entity])) {
       $tableName = CRM_Core_DAO_AllCoreTables::getTableForEntityName($entity);
       $used_for = CRM_Core_OptionGroup::values('tag_used_for');
       Civi::$statics[__CLASS__]['tagged_entities'][$entity] = !empty($used_for[$tableName]) ? $tableName : FALSE;
     }
 
-    if (Civi::$statics[__CLASS__]['tagged_entities'][$entity]) {
+    if (!empty(Civi::$statics[__CLASS__]['tagged_entities'][$entity])) {
       CRM_Core_DAO::executeQuery('DELETE FROM civicrm_entity_tag WHERE entity_table = %1 AND entity_id = %2',
         [1 => [Civi::$statics[__CLASS__]['tagged_entities'][$entity], 'String'], 2 => [$event->object->id, 'Integer']]
       );
index 6a274847fc90b144f76572ace94967515a653aa8..febcb374a83cf9c00cea933e419b1fb693b5bbb3 100644 (file)
@@ -56,17 +56,17 @@ class CRM_Core_DAO_AllCoreTables {
   /**
    * (Quasi-Private) Do not call externally (except for unit-testing)
    *
-   * @param string $daoName
+   * @param string $briefName
    * @param string $className
    * @param string $tableName
    * @param string $fields_callback
    * @param string $links_callback
    */
-  public static function registerEntityType($daoName, $className, $tableName, $fields_callback = NULL, $links_callback = NULL) {
-    self::$daoToClass[$daoName] = $className;
+  public static function registerEntityType($briefName, $className, $tableName, $fields_callback = NULL, $links_callback = NULL) {
+    self::$daoToClass[$briefName] = $className;
     self::$tables[$tableName] = $className;
-    self::$entityTypes[$className] = [
-      'name' => $daoName,
+    self::$entityTypes[$briefName] = [
+      'name' => $briefName,
       'class' => $className,
       'table' => $tableName,
       'fields_callback' => $fields_callback,
@@ -76,7 +76,7 @@ class CRM_Core_DAO_AllCoreTables {
 
   /**
    * @return array
-   *   Ex: $result['CRM_Contact_DAO_Contact']['table'] == 'civicrm_contact';
+   *   Ex: $result['Contact']['table'] == 'civicrm_contact';
    */
   public static function get() {
     self::init();
@@ -317,7 +317,8 @@ class CRM_Core_DAO_AllCoreTables {
    *   Ex: 'CRM_Contact_DAO_Contact'.
    */
   public static function getFullName($briefName) {
-    return self::daoToClass()[$briefName] ?? NULL;
+    self::init();
+    return self::$entityTypes[$briefName]['class'] ?? NULL;
   }
 
   /**
@@ -345,12 +346,13 @@ class CRM_Core_DAO_AllCoreTables {
   /**
    * Convert the entity name into a table name.
    *
-   * @param string $entityBriefName
+   * @param string $briefName
    *
    * @return FALSE|string
    */
-  public static function getTableForEntityName($entityBriefName) {
-    return self::getTableForClass(self::getFullName($entityBriefName));
+  public static function getTableForEntityName($briefName) {
+    self::init();
+    return self::$entityTypes[$briefName]['table'];
   }
 
   /**
@@ -361,7 +363,9 @@ class CRM_Core_DAO_AllCoreTables {
    * @return FALSE|string
    */
   public static function getEntityNameForTable(string $tableName) {
-    return self::getBriefName(self::getClassForTable($tableName));
+    self::init();
+    $matches = CRM_Utils_Array::findAll(self::$entityTypes, ['table' => $tableName]);
+    return $matches ? $matches[0]['name'] : NULL;
   }
 
   /**
@@ -456,14 +460,18 @@ class CRM_Core_DAO_AllCoreTables {
    *
    * Apply any third-party alterations to the `fields()`.
    *
+   * TODO: This function should probably take briefName as the key instead of className
+   * because the latter is not always unique (e.g. virtual entities)
+   *
    * @param string $className
    * @param string $event
    * @param mixed $values
    */
   public static function invoke($className, $event, &$values) {
     self::init();
-    if (isset(self::$entityTypes[$className][$event])) {
-      foreach (self::$entityTypes[$className][$event] as $filter) {
+    $briefName = self::getBriefName($className);
+    if (isset(self::$entityTypes[$briefName][$event])) {
+      foreach (self::$entityTypes[$briefName][$event] as $filter) {
         $args = [$className, &$values];
         \Civi\Core\Resolver::singleton()->call($filter, $args);
       }
index 87c2816ab68855429466545a090bee40ae36e193..d9baef14cd45dc57a13a4d6b76635fe8f9cd0000 100644 (file)
@@ -58,9 +58,9 @@ class SchemaMapBuilder {
    */
   private function loadTables(SchemaMap $map) {
     /** @var \CRM_Core_DAO $daoName */
-    foreach (AllCoreTables::get() as $daoName => $data) {
+    foreach (AllCoreTables::get() as $data) {
       $table = new Table($data['table']);
-      foreach ($daoName::fields() as $fieldData) {
+      foreach ($data['class']::fields() as $fieldData) {
         $this->addJoins($table, $fieldData['name'], $fieldData);
       }
       $map->addTable($table);
index 6457a85fb141d70cce2fa8aed766199316d79278..612b2c3cf7f67214cdb58c5bff8a41ad5b5a9082 100644 (file)
@@ -216,6 +216,18 @@ class CRM_Core_DAO_AllCoreTablesTest extends CiviUnitTestCase {
   public function testGetBriefName() {
     $this->assertEquals('Contact', CRM_Core_DAO_AllCoreTables::getBriefName('CRM_Contact_BAO_Contact'));
     $this->assertEquals('Contact', CRM_Core_DAO_AllCoreTables::getBriefName('CRM_Contact_DAO_Contact'));
+    $this->assertNull(CRM_Core_DAO_AllCoreTables::getBriefName('CRM_Core_DAO_XqZy'));
+  }
+
+  public function testGetFullName() {
+    $this->assertEquals('CRM_Contact_DAO_Contact', CRM_Core_DAO_AllCoreTables::getFullName('Contact'));
+    $this->assertNull(CRM_Core_DAO_AllCoreTables::getFullName('XqZy'));
+  }
+
+  public function testGetEntityNameForTable() {
+    $this->assertEquals('Contact', CRM_Core_DAO_AllCoreTables::getEntityNameForTable('civicrm_contact'));
+    $this->assertEquals('RelationshipCache', CRM_Core_DAO_AllCoreTables::getEntityNameForTable('civicrm_relationship_cache'));
+    $this->assertNull(CRM_Core_DAO_AllCoreTables::getEntityNameForTable('civicrm_invalid_table'));
   }
 
 }