Move customSearch smart group sql generation to legacycustomsearches extension
authorEileen McNaughton <emcnaughton@wikimedia.org>
Thu, 22 Jun 2023 23:23:39 +0000 (16:23 -0700)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Thu, 22 Jun 2023 23:26:46 +0000 (16:26 -0700)
CRM/Contact/BAO/GroupContactCache.php
CRM/Utils/Hook.php
ext/legacycustomsearches/legacycustomsearches.php

index 8fc361e64ba365760e05a2d75a4ea3300dc7b98d..f29a78274659d7ab677a1deb3d3d503c74cb0ad8 100644 (file)
@@ -532,41 +532,6 @@ ORDER BY   gc.contact_id, g.children
     return "SELECT $addSelect, `$idField` AS contact_id FROM ($sql) api_query";
   }
 
-  /**
-   * Get sql from a custom search.
-   *
-   * We split it up and store custom class
-   * so temp tables are not destroyed if they are used
-   *
-   * @param array $savedSearch
-   * @param int $groupID
-   *
-   * @return string
-   * @throws \CRM_Core_Exception
-   */
-  protected static function getCustomSearchSQL(array $savedSearch, int $groupID) {
-    $savedSearchID = $savedSearch['id'];
-    $excludeClause = "NOT IN (
-                        SELECT contact_id FROM civicrm_group_contact
-                        WHERE civicrm_group_contact.status = 'Removed'
-                        AND civicrm_group_contact.group_id = $groupID )";
-    $addSelect = "$groupID AS group_id";
-    $ssParams = CRM_Contact_BAO_SavedSearch::getFormValues($savedSearchID);
-    // CRM-7021 rectify params to what proximity search expects if there is a value for prox_distance
-    if (!empty($ssParams)) {
-      CRM_Contact_BAO_ProximityQuery::fixInputParams($ssParams);
-    }
-    $searchSQL = CRM_Contact_BAO_SearchCustom::customClass($ssParams['customSearchID'], $savedSearchID)->contactIDs();
-    $searchSQL = str_replace('ORDER BY contact_a.id ASC', '', $searchSQL);
-    if (strpos($searchSQL, 'WHERE') === FALSE) {
-      $searchSQL .= " WHERE contact_a.id $excludeClause";
-    }
-    else {
-      $searchSQL .= " AND contact_a.id $excludeClause";
-    }
-    return preg_replace("/^\s*SELECT /", "SELECT $addSelect, ", $searchSQL);
-  }
-
   /**
    * Get array of sql from a saved query object group.
    *
@@ -797,14 +762,20 @@ ORDER BY   gc.contact_id, g.children
         ->execute()
         ->first();
 
-      if ($savedSearch['api_entity']) {
-        $sql = self::getApiSQL($savedSearch, $groupID);
-      }
-      elseif (!empty($savedSearch['search_custom_id'])) {
-        $sql = self::getCustomSearchSQL($savedSearch, $groupID);
-      }
-      else {
-        $sql = self::getQueryObjectSQL($savedSearch, $groupID);
+      $sql = '';
+      CRM_Utils_Hook::buildGroupContactCache($savedSearch, $groupID, $sql);
+      if (!$sql) {
+        if ($savedSearch['api_entity']) {
+          $sql = self::getApiSQL($savedSearch, $groupID);
+        }
+        elseif (!empty($savedSearch['search_custom_id'])) {
+          Group::update(FALSE)->addWhere('id', '=', $groupID)->setValues(['is_active' => FALSE])->execute();
+          CRM_Core_Session::setStatus(ts('Invalid group %1 found and disabled'), [1 => $groupID]);
+          return;
+        }
+        else {
+          $sql = self::getQueryObjectSQL($savedSearch, $groupID);
+        }
       }
     }
 
index a03e2fbccb7692f112932bcfbc66ca4b01c52198..94039470135b46944040ce363cca79d8d3bf2ae3 100644 (file)
@@ -1768,6 +1768,38 @@ abstract class CRM_Utils_Hook {
     );
   }
 
+  /**
+   * Build the group contact cache for the relevant group.
+   *
+   * This hook allows a listener to specify the sql to be used to build a group in
+   * the group contact cache.
+   *
+   * If sql is altered then the api / bao query methods of building the cache will not
+   * be called.
+   *
+   * An example of the sql it might be set to is:
+   *
+   * SELECT 7 AS group_id, contact_a.id as contact_id
+   * FROM  civicrm_contact contact_a
+   * WHERE contact_a.contact_type   = 'Household' AND contact_a.household_name LIKE '%' AND  ( 1 )  ORDER BY contact_a.id
+   * AND contact_a.id
+   *   NOT IN (
+   *   SELECT contact_id FROM civicrm_group_contact
+   *   WHERE civicrm_group_contact.status = 'Removed'
+   *   AND civicrm_group_contact.group_id = 7 )
+   *
+   * @param array $savedSearch
+   * @param int $groupID
+   * @param string $sql
+   */
+  public static function buildGroupContactCache(array $savedSearch, int $groupID, string &$sql): void {
+    $null = NULL;
+    self::singleton()->invoke(['savedSearch', 'groupID', 'sql'], $savedSearch, $groupID,
+      $sql, $null, $null, $null,
+      'civicrm_buildGroupContactCache'
+    );
+  }
+
   /**
    * (EXPERIMENTAL) Scan extensions for a list of auto-registered interfaces.
    *
index 9d16959ce51fc0926d894f6a085d8a915e71fb3d..056049c041f5ca7b9e7c021ab3817403e6dfb840 100644 (file)
@@ -31,3 +31,38 @@ function legacycustomsearches_civicrm_install() {
 function legacycustomsearches_civicrm_enable() {
   _legacycustomsearches_civix_civicrm_enable();
 }
+
+/**
+ * Determine the sql
+ * @param array $savedSearch
+ * @param int $groupID
+ * @param string $sql
+ *
+ * @throws \CRM_Core_Exception
+ */
+function legacycustomsearches_civicrm_buildGroupContactCache(array $savedSearch, int $groupID, string &$sql): void {
+  if (empty($savedSearch['search_custom_id'])) {
+    return;
+  }
+  $savedSearchID = $savedSearch['id'];
+  $excludeClause = "
+    NOT IN (
+    SELECT contact_id FROM civicrm_group_contact
+    WHERE civicrm_group_contact.status = 'Removed'
+    AND civicrm_group_contact.group_id = $groupID )";
+  $addSelect = "$groupID AS group_id";
+  $ssParams = CRM_Contact_BAO_SavedSearch::getFormValues($savedSearchID);
+  // CRM-7021 rectify params to what proximity search expects if there is a value for prox_distance
+  if (!empty($ssParams)) {
+    CRM_Contact_BAO_ProximityQuery::fixInputParams($ssParams);
+  }
+  $searchSQL = CRM_Contact_BAO_SearchCustom::customClass($ssParams['customSearchID'], $savedSearchID)->contactIDs();
+  $searchSQL = str_replace('ORDER BY contact_a.id ASC', '', $searchSQL);
+  if (strpos($searchSQL, 'WHERE') === FALSE) {
+    $searchSQL .= " WHERE contact_a.id $excludeClause";
+  }
+  else {
+    $searchSQL .= " AND contact_a.id $excludeClause";
+  }
+  $sql = preg_replace("/^\s*SELECT /", "SELECT $addSelect, ", $searchSQL);
+}