<?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 {
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
* 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;
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 ) ";
]);
}
+ /**
+ * @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;
+ }
+
}