Add unique constraint on ufmatch user ID
authorMatthew Wire <mjw@mjwconsult.co.uk>
Wed, 6 Dec 2023 12:14:22 +0000 (12:14 +0000)
committerMatthew Wire <mjw@mjwconsult.co.uk>
Thu, 7 Dec 2023 14:36:37 +0000 (14:36 +0000)
CRM/Core/BAO/UFMatch.php
CRM/Core/DAO/UFMatch.php
CRM/Utils/Check/Component/Cms.php
xml/schema/Core/UFMatch.xml

index 6290430fd0d7f89cc56d562cdc6249f1597eb618..3d874a6d658d2259c20d1f9fe7ec06c7a8188d8f 100644 (file)
@@ -627,4 +627,32 @@ AND    domain_id    = %4
     return $clauses;
   }
 
+  /**
+   * This checks and adds a unique index on (uf_id,domain_id)
+   *
+   * @return bool
+   * @throws \Civi\Core\Exception\DBQueryException
+   */
+  public static function tryToAddUniqueIndexOnUfId(): bool {
+    if (!CRM_Core_BAO_SchemaHandler::checkIfIndexExists('civicrm_uf_match', 'UI_uf_match_uf_id_domain_id')) {
+      // Run a query to check if we have duplicates
+      $query = 'SELECT COUNT(*) FROM civicrm_uf_match
+GROUP BY uf_id,domain_id
+HAVING COUNT(*) > 1';
+      $dao = CRM_Core_DAO::executeQuery($query);
+      if ($dao->fetch()) {
+        // Tell the user they need to fix it manually
+        \Civi::log()->error('You have multiple records with the same uf_id in civicrm_uf_match. You need to manually fix this in the database so that uf_id is unique.');
+        return FALSE;
+      }
+      else {
+        // Add the unique index
+        CRM_Core_DAO::executeQuery("
+        ALTER TABLE civicrm_uf_match ADD UNIQUE INDEX UI_uf_match_uf_id_domain_id (uf_id,domain_id);
+      ");
+      }
+    }
+    return TRUE;
+  }
+
 }
index aaa71a8278f2c0b605534cdbf532663ea5c20329..58948427a7267a76965875ebcaf035ce3bb68ed5 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/UFMatch.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:ddf0ceeb22715a1ee0b7b93c90df31f2)
+ * (GenCodeChecksum:19280813191bcf496c8e43eb9778157a)
  */
 
 /**
@@ -336,6 +336,15 @@ class CRM_Core_DAO_UFMatch extends CRM_Core_DAO {
         'localizable' => FALSE,
         'sig' => 'civicrm_uf_match::0::uf_id',
       ],
+      'UI_uf_match_uf_id_domain_id' => [
+        'name' => 'UI_uf_match_uf_id_domain_id',
+        'field' => [
+          0 => 'uf_id',
+          1 => 'domain_id',
+        ],
+        'localizable' => FALSE,
+        'sig' => 'civicrm_uf_match::0::uf_id::domain_id',
+      ],
       'UI_uf_name_domain_id' => [
         'name' => 'UI_uf_name_domain_id',
         'field' => [
index d69083c46249ee9a6311ce98e9af591751c52258..68e737c4639f9779f310554a6396fdc6542456ae 100644 (file)
@@ -200,4 +200,31 @@ class CRM_Utils_Check_Component_Cms extends CRM_Utils_Check_Component {
     return (int) ($basePage->post_status == 'publish');
   }
 
+  /**
+   * Check if we created unique index on civicrm_uf_match (uf_id,domain_id)
+   *
+   * @return CRM_Utils_Check_Message[]
+   */
+  public static function checkUfMatchUnique(): array {
+    $checks = [];
+
+    if (CRM_Core_BAO_UFMatch::tryToAddUniqueIndexOnUfId()) {
+      // Already done. Success!
+      return $checks;
+    }
+
+    // Your DB has multiple uf_match records! Bad
+    $checks[] = new CRM_Utils_Check_Message(
+      __FUNCTION__,
+      ts('You have multiple records with the same uf_id in civicrm_uf_match. You need to manually fix this in the database so that uf_id is unique') .
+      ' ' .
+      CRM_Utils_System::docURL2('sysadmin/upgrade/todo/#todo'),
+      ts('Duplicate records in UFMatch'),
+      \Psr\Log\LogLevel::ERROR,
+      'fa-database'
+    );
+
+    return $checks;
+  }
+
 }
index 6133aab373d87af80a06d389e66ab32daff24784..ef10a14b7561a3bdf795b01d9b792312b6eea069 100644 (file)
     <fieldName>uf_id</fieldName>
     <add>3.3</add>
   </index>
+  <index>
+    <name>UI_uf_match_uf_id_domain_id</name>
+    <fieldName>uf_id</fieldName>
+    <fieldName>domain_id</fieldName>
+    <add>5.69</add>
+  </index>
   <field>
     <name>uf_name</name>
     <title>CMS Unique Identifier</title>