Merge pull request #16759 from eileenmcnaughton/fatal2
[civicrm-core.git] / CRM / Contact / BAO / GroupContactCache.php
index b873b26451dce77e0cc42e3d5845be6b782df29e..3234710a6b650223c9bdb842b3a8bb114b1302a1 100644 (file)
@@ -1,34 +1,18 @@
 <?php
 /*
  +--------------------------------------------------------------------+
- | CiviCRM version 5                                                  |
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2020                                |
- +--------------------------------------------------------------------+
- | This file is a part of CiviCRM.                                    |
- |                                                                    |
- | CiviCRM is free software; you can copy, modify, and distribute it  |
- | under the terms of the GNU Affero General Public License           |
- | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ | Copyright CiviCRM LLC. All rights reserved.                        |
  |                                                                    |
- | CiviCRM is distributed in the hope that it will be useful, but     |
- | WITHOUT ANY WARRANTY; without even the implied warranty of         |
- | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
- | See the GNU Affero General Public License for more details.        |
- |                                                                    |
- | You should have received a copy of the GNU Affero General Public   |
- | License and the CiviCRM Licensing Exception along                  |
- | with this program; if not, contact CiviCRM LLC                     |
- | at info[AT]civicrm[DOT]org. If you have questions about the        |
- | GNU Affero General Public License or the licensing of CiviCRM,     |
- | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
  +--------------------------------------------------------------------+
  */
 
 /**
  *
  * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2020
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
  */
 class CRM_Contact_BAO_GroupContactCache extends CRM_Contact_DAO_GroupContactCache {
 
@@ -282,23 +266,6 @@ WHERE  id IN ( $groupIDs )
     CRM_Core_DAO::executeQuery($sql);
   }
 
-  /**
-   * @deprecated function - the best function to call is
-   * CRM_Contact_BAO_Contact::updateContactCache at the moment, or api job.group_cache_flush
-   * to really force a flush.
-   *
-   * Remove this function altogether by mid 2018.
-   *
-   * However, if updating code outside core to use this (or any BAO function) it is recommended that
-   * you add an api call to lock in into our contract. Currently there is not really a supported
-   * method for non core functions.
-   */
-  public static function remove() {
-    Civi::log()
-      ->warning('Deprecated code. This function should not be called without groupIDs. Extensions can use the api job.group_cache_flush for a hard flush or add an api option for soft flush', ['civi.tag' => 'deprecated']);
-    CRM_Contact_BAO_GroupContactCache::opportunisticCacheFlush();
-  }
-
   /**
    * Function to clear group contact cache and reset the corresponding
    *  group's cache and refresh date
@@ -472,6 +439,8 @@ WHERE  id IN ( $groupIDs )
    *   The smart group that needs to be loaded.
    * @param bool $force
    *   Should we force a search through.
+   *
+   * @throws \CRM_Core_Exception
    */
   public static function load(&$group, $force = FALSE) {
     $groupID = $group->id;
@@ -493,68 +462,25 @@ WHERE  id IN ( $groupIDs )
     if ($savedSearchID) {
       $ssParams = CRM_Contact_BAO_SavedSearch::getSearchParams($savedSearchID);
 
-      // rectify params to what proximity search expects if there is a value for prox_distance
-      // CRM-7021
-      if (!empty($ssParams)) {
-        CRM_Contact_BAO_ProximityQuery::fixInputParams($ssParams);
-      }
-
-      $returnProperties = [];
-      if (CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $savedSearchID, 'mapping_id')) {
-        $fv = CRM_Contact_BAO_SavedSearch::getFormValues($savedSearchID);
-        $returnProperties = CRM_Core_BAO_Mapping::returnProperties($fv);
-      }
-
-      if (isset($ssParams['customSearchID'])) {
-        // if custom search
-
-        // we split it up and store custom class
-        // so temp tables are not destroyed if they are used
-        // hence customClass is defined above at top of function
-        $customClass = CRM_Contact_BAO_SearchCustom::customClass($ssParams['customSearchID'], $savedSearchID);
-        $searchSQL = $customClass->contactIDs();
-        $searchSQL = str_replace('ORDER BY contact_a.id ASC', '', $searchSQL);
-        if (!strstr($searchSQL, 'WHERE')) {
-          $searchSQL .= " WHERE ( 1 ) ";
-        }
-        $sql = [
-          'select' => substr($searchSQL, 0, strpos($searchSQL, 'FROM')),
-          'from' => substr($searchSQL, strpos($searchSQL, 'FROM')),
-        ];
+      if (!empty($ssParams['api_entity'])) {
+        $mainCol = 'a';
+        $sql = self::getApiSQL($savedSearchID, $ssParams);
       }
       else {
-        $formValues = CRM_Contact_BAO_SavedSearch::getFormValues($savedSearchID);
-        // CRM-17075 using the formValues in this way imposes extra logic and complexity.
-        // we have the where_clause and where tables stored in the saved_search table
-        // and should use these rather than re-processing the form criteria (which over-works
-        // the link between the form layer & the query layer too).
-        // It's hard to think of when you would want to use anything other than return
-        // properties = array('contact_id' => 1) here as the point would appear to be to
-        // generate the list of contact ids in the group.
-        // @todo review this to use values in saved_search table (preferably for 4.8).
-        $query
-          = new CRM_Contact_BAO_Query(
-            $ssParams, $returnProperties, NULL,
-            FALSE, FALSE, 1,
-            TRUE, TRUE,
-            FALSE,
-            CRM_Utils_Array::value('display_relationship_type', $formValues),
-            CRM_Utils_Array::value('operator', $formValues, 'AND')
-          );
-        $query->_useDistinct = FALSE;
-        $query->_useGroupBy = FALSE;
-        $sqlParts = $query->getSearchSQLParts(
-            0, 0, NULL,
-            FALSE, FALSE,
-            FALSE, TRUE
-          );
-        $sql = [
-          'select' => $sqlParts['select'],
-          'from' => "{$sqlParts['from']} {$sqlParts['where']} {$sqlParts['having']} {$sqlParts['group_by']}",
-        ];
+        $mainCol = 'contact_a';
+        // 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);
+        }
+        if (isset($ssParams['customSearchID'])) {
+          $sql = self::getCustomSearchSQL($savedSearchID, $ssParams);
+        }
+        else {
+          $sql = self::getQueryObjectSQL($savedSearchID, $ssParams);
+        }
       }
       $groupID = CRM_Utils_Type::escape($groupID, 'Integer');
-      $sql['from'] .= " AND contact_a.id NOT IN (
+      $sql['from'] .= " AND $mainCol.id NOT IN (
                           SELECT contact_id FROM civicrm_group_contact
                           WHERE civicrm_group_contact.status = 'Removed'
                           AND   civicrm_group_contact.group_id = $groupID ) ";
@@ -791,4 +717,103 @@ ORDER BY   gc.contact_id, g.children
       ]);
   }
 
+  /**
+   * @param $savedSearchID
+   * @param array $savedSearch
+   * @return array
+   * @throws API_Exception
+   * @throws \Civi\API\Exception\NotImplementedException
+   * @throws CRM_Core_Exception
+   */
+  protected static function getApiSQL($savedSearchID, array $savedSearch): array {
+    $api = \Civi\API\Request::create($savedSearch['api_entity'], 'get', $savedSearch['api_params']);
+    $query = new \Civi\Api4\Query\Api4SelectQuery($api->getEntityName(), FALSE, $api->entityFields());
+    $query->select = ['id'];
+    $query->where = $api->getWhere();
+    $query->orderBy = $api->getOrderBy();
+    $query->limit = $api->getLimit();
+    $query->offset = $api->getOffset();
+    $sql = $query->getSql();
+    return [
+      'select' => substr($sql, 0, strpos($sql, 'FROM')),
+      'from' => substr($sql, strpos($sql, 'FROM')),
+    ];
+  }
+
+  /**
+   * Get sql from a custom search.
+   *
+   * @param int $savedSearchID
+   * @param array $ssParams
+   *
+   * @return array
+   * @throws \Exception
+   */
+  protected static function getCustomSearchSQL($savedSearchID, array $ssParams): array {
+    // if custom search
+
+    // we split it up and store custom class
+    // so temp tables are not destroyed if they are used
+    // hence customClass is defined above at top of function
+    $customClass = CRM_Contact_BAO_SearchCustom::customClass($ssParams['customSearchID'], $savedSearchID);
+    $searchSQL = $customClass->contactIDs();
+    $searchSQL = str_replace('ORDER BY contact_a.id ASC', '', $searchSQL);
+    if (strpos($searchSQL, 'WHERE') === FALSE) {
+      $searchSQL .= " WHERE ( 1 ) ";
+    }
+    $sql = [
+      'select' => substr($searchSQL, 0, strpos($searchSQL, 'FROM')),
+      'from' => substr($searchSQL, strpos($searchSQL, 'FROM')),
+    ];
+    return $sql;
+  }
+
+  /**
+   * Get array of sql from a saved query object group.
+   *
+   * @param int $savedSearchID
+   * @param array $ssParams
+   *
+   * @return array
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
+   */
+  protected static function getQueryObjectSQL($savedSearchID, array $ssParams): array {
+    $returnProperties = NULL;
+    if (CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_SavedSearch', $savedSearchID, 'mapping_id')) {
+      $fv = CRM_Contact_BAO_SavedSearch::getFormValues($savedSearchID);
+      $returnProperties = CRM_Core_BAO_Mapping::returnProperties($fv);
+    }
+    $formValues = CRM_Contact_BAO_SavedSearch::getFormValues($savedSearchID);
+    // CRM-17075 using the formValues in this way imposes extra logic and complexity.
+    // we have the where_clause and where tables stored in the saved_search table
+    // and should use these rather than re-processing the form criteria (which over-works
+    // the link between the form layer & the query layer too).
+    // It's hard to think of when you would want to use anything other than return
+    // properties = array('contact_id' => 1) here as the point would appear to be to
+    // generate the list of contact ids in the group.
+    // @todo review this to use values in saved_search table (preferably for 4.8).
+    $query
+      = new CRM_Contact_BAO_Query(
+      $ssParams, $returnProperties, NULL,
+      FALSE, FALSE, 1,
+      TRUE, TRUE,
+      FALSE,
+      CRM_Utils_Array::value('display_relationship_type', $formValues),
+      CRM_Utils_Array::value('operator', $formValues, 'AND')
+    );
+    $query->_useDistinct = FALSE;
+    $query->_useGroupBy = FALSE;
+    $sqlParts = $query->getSearchSQLParts(
+      0, 0, NULL,
+      FALSE, FALSE,
+      FALSE, TRUE
+    );
+    $sql = [
+      'select' => $sqlParts['select'],
+      'from' => "{$sqlParts['from']} {$sqlParts['where']} {$sqlParts['having']} {$sqlParts['group_by']}",
+    ];
+    return $sql;
+  }
+
 }