/** * Fill the acl contact cache for this contact id if empty. * * @param int $userID * @param int|string $type the type of operation (view|edit) * @param bool $force * Should we force a recompute. */ public static function cache($userID, $type = CRM_Core_Permission::VIEW, $force = FALSE) { static $_processed = array(); if ($type = CRM_Core_Permission::VIEW) { $operationClause = " operation IN ( 'Edit', 'View' ) "; $operation = 'View'; } else { $operationClause = " operation = 'Edit' "; $operation = 'Edit'; } if (!$force) { if (!empty($_processed[$userID])) { return; } // run a query to see if the cache is filled $sql = "\nSELECT count(id)\nFROM civicrm_acl_contact_cache\nWHERE user_id = %1\nAND {$operationClause}\n"; $params = array(1 => array($userID, 'Integer')); $count = CRM_Core_DAO::singleValueQuery($sql, $params); if ($count > 0) { $_processed[$userID] = 1; return; } } $tables = array(); $whereTables = array(); $permission = CRM_ACL_API::whereClause($type, $tables, $whereTables, $userID); $from = CRM_Contact_BAO_Query::fromClause($whereTables); CRM_Core_DAO::executeQuery("\nINSERT INTO civicrm_acl_contact_cache ( user_id, contact_id, operation )\nSELECT {$userID} as user_id, contact_a.id as contact_id, '{$operation}' as operation\n {$from}\nWHERE {$permission}\nGROUP BY contact_a.id\nON DUPLICATE KEY UPDATE\n user_id=VALUES(user_id),\n contact_id=VALUES(contact_id),\n operation=VALUES(operation)"); $_processed[$userID] = 1; }
/** * create and query the db for an contact search * * @param int $offset the offset for the query * @param int $rowCount the number of rows to return * @param string $sort the order by string * @param boolean $count is this a count only query ? * @param boolean $includeContactIds should we include contact ids? * @param boolean $sortByChar if true returns the distinct array of first characters for search results * @param boolean $groupContacts if true, use a single mysql group_concat statement to get the contact ids * @param boolean $returnQuery should we return the query as a string * @param string $additionalWhereClause if the caller wants to further restrict the search (used for components) * @param string $additionalFromClause should be clause with proper joins, effective to reduce where clause load. * * @return CRM_Contact_DAO_Contact * @access public */ function searchQuery($offset = 0, $rowCount = 0, $sort = NULL, $count = FALSE, $includeContactIds = FALSE, $sortByChar = FALSE, $groupContacts = FALSE, $returnQuery = FALSE, $additionalWhereClause = NULL, $sortOrder = NULL, $additionalFromClause = NULL, $skipOrderAndLimit = FALSE) { if ($includeContactIds) { $this->_includeContactIds = TRUE; $this->_whereClause = $this->whereClause(); } // hack for now, add permission only if we are in search // FIXME: we should actually filter out deleted contacts (unless requested to do the opposite) $permission = ' ( 1 ) '; $onlyDeleted = FALSE; $onlyDeleted = in_array(array('deleted_contacts', '=', '1', '0', '0'), $this->_params); // if we’re explicitely looking for a certain contact’s contribs, events, etc. // and that contact happens to be deleted, set $onlyDeleted to true foreach ($this->_params as $values) { list($name, $op, $value, $_, $_) = $values; if ($name == 'contact_id' and $op == '=') { if (CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $value, 'is_deleted')) { $onlyDeleted = TRUE; } break; } } if (!$this->_skipPermission) { $permission = CRM_ACL_API::whereClause(CRM_Core_Permission::VIEW, $this->_tables, $this->_whereTables, NULL, $onlyDeleted, $this->_skipDeleteClause); // CRM_Core_Error::debug( 'p', $permission ); // CRM_Core_Error::debug( 't', $this->_tables ); // CRM_Core_Error::debug( 'w', $this->_whereTables ); // regenerate fromClause since permission might have added tables if ($permission) { //fix for row count in qill (in contribute/membership find) if (!$count) { $this->_useDistinct = TRUE; } $this->_fromClause = self::fromClause($this->_tables, NULL, NULL, $this->_primaryLocation, $this->_mode); $this->_simpleFromClause = self::fromClause($this->_whereTables, NULL, NULL, $this->_primaryLocation, $this->_mode); } } else { // add delete clause if needed even if we are skipping permission // CRM-7639 if (!$this->_skipDeleteClause) { if (CRM_Core_Permission::check('access deleted contacts') and $onlyDeleted) { $permission = '(contact_a.is_deleted)'; } else { // CRM-6181 $permission = '(contact_a.is_deleted = 0)'; } } } list($select, $from, $where, $having) = $this->query($count, $sortByChar, $groupContacts); //additional from clause should be w/ proper joins. if ($additionalFromClause) { $from .= "\n" . $additionalFromClause; } if (empty($where)) { $where = "WHERE {$permission}"; } else { $where = "{$where} AND {$permission}"; } // CRM_Core_Error::debug( 't', $this ); // CRM_Core_Error::debug( 'w', $where ); // CRM_Core_Error::debug( 'a', $additionalWhereClause ); if ($additionalWhereClause) { $where = $where . ' AND ' . $additionalWhereClause; } // building the query string $groupBy = NULL; if (!$count) { if (isset($this->_groupByComponentClause)) { $groupBy = $this->_groupByComponentClause; } elseif ($this->_useGroupBy) { $groupBy = ' GROUP BY contact_a.id'; } } if ($this->_mode & CRM_Contact_BAO_Query::MODE_ACTIVITY && !$count) { $groupBy = 'GROUP BY civicrm_activity.id '; } $order = $orderBy = $limit = ''; if (!$count) { $config = CRM_Core_Config::singleton(); if ($config->includeOrderByClause || isset($this->_distinctComponentClause)) { if ($sort) { if (is_string($sort)) { $orderBy = $sort; } else { $orderBy = trim($sort->orderBy()); } if (!empty($orderBy)) { // this is special case while searching for // changelog CRM-1718 if (preg_match('/sort_name/i', $orderBy)) { $orderBy = str_replace('sort_name', 'contact_a.sort_name', $orderBy); } $order = " ORDER BY {$orderBy}"; if ($sortOrder) { $order .= " {$sortOrder}"; } // always add contact_a.id to the ORDER clause // so the order is deterministic if (strpos('contact_a.id', $order) === FALSE) { $order .= ", contact_a.id"; } } } elseif ($sortByChar) { $order = " ORDER BY UPPER(LEFT(contact_a.sort_name, 1)) asc"; } else { $order = " ORDER BY contact_a.sort_name asc, contact_a.id"; } } $doOpt = TRUE; // hack for order clause if ($order) { $fieldStr = trim(str_replace('ORDER BY', '', $order)); $fieldOrder = explode(' ', $fieldStr); $field = $fieldOrder[0]; if ($field) { switch ($field) { case 'sort_name': case 'id': case 'contact_a.sort_name': case 'contact_a.id': break; case 'city': case 'postal_code': $this->_whereTables["civicrm_address"] = 1; $order = str_replace($field, "civicrm_address.{$field}", $order); break; case 'country': case 'state_province': $this->_whereTables["civicrm_{$field}"] = 1; $order = str_replace($field, "civicrm_{$field}.name", $order); break; case 'email': $this->_whereTables["civicrm_email"] = 1; $order = str_replace($field, "civicrm_email.{$field}", $order); break; default: $doOpt = FALSE; } } } if ($rowCount > 0 && $offset >= 0) { $limit = " LIMIT {$offset}, {$rowCount} "; // ok here is a first hack at an optimization, lets get all the contact ids // that are restricted and we'll then do the final clause with it // CRM-5954 if (isset($this->_distinctComponentClause)) { if (strpos($this->_distinctComponentClause, 'DISTINCT') == FALSE) { $limitSelect = "SELECT DISTINCT {$this->_distinctComponentClause}"; } else { $limitSelect = "SELECT {$this->_distinctComponentClause}"; } } else { $limitSelect = 'SELECT DISTINCT contact_a.id as id'; } if ($doOpt) { $this->_simpleFromClause = self::fromClause($this->_whereTables, NULL, NULL, $this->_primaryLocation, $this->_mode); if ($additionalFromClause) { $this->_simpleFromClause .= "\n" . $additionalFromClause; } // if we are doing a transform, do it here // CRM-7969 $having = NULL; if ($this->_displayRelationshipType) { $this->filterRelatedContacts($this->_simpleFromClause, $where, $having); } $limitQuery = "{$limitSelect} {$this->_simpleFromClause} {$where} {$groupBy} {$order} {$limit}"; $limitDAO = CRM_Core_DAO::executeQuery($limitQuery); $limitIDs = array(); while ($limitDAO->fetch()) { $limitIDs[] = $limitDAO->id; } if (empty($limitIDs)) { $limitClause = ' AND ( 0 ) '; } else { if (isset($this->_distinctComponentClause)) { $limitClause = " AND {$this->_distinctComponentClause} IN ( "; } else { $limitClause = ' AND contact_a.id IN ( '; } $limitClause .= implode(',', $limitIDs) . ' ) '; } $where .= $limitClause; // reset limit clause since we already restrict what records we want $limit = NULL; } } } // if we are doing a transform, do it here // use the $from, $where and $having to get the contact ID if ($this->_displayRelationshipType) { $this->filterRelatedContacts($from, $where, $having); } if ($skipOrderAndLimit) { $query = "{$select} {$from} {$where} {$having} {$groupBy}"; } else { $query = "{$select} {$from} {$where} {$having} {$groupBy} {$order} {$limit}"; } // CRM_Core_Error::debug('query', $query); // CRM_Core_Error::debug('query', $where); // CRM_Core_Error::debug('this', $this ); if ($returnQuery) { return $query; } if ($count) { return CRM_Core_DAO::singleValueQuery($query); } $dao = CRM_Core_DAO::executeQuery($query); if ($groupContacts) { $ids = array(); while ($dao->fetch()) { $ids[] = $dao->id; } return implode(',', $ids); } return $dao; }
/** * Populate $this->_permissionWhereClause with permission related clause and update other * query related properties. * * Function calls ACL permission class and hooks to filter the query appropriately * * Note that these 2 params were in the code when extracted from another function * and a second round extraction would be to make them properties of the class * * @param bool $onlyDeleted * Only get deleted contacts. * @param bool $count * Return Count only. */ public function generatePermissionClause($onlyDeleted = FALSE, $count = FALSE) { if (!$this->_skipPermission) { $this->_permissionWhereClause = CRM_ACL_API::whereClause(CRM_Core_Permission::VIEW, $this->_tables, $this->_whereTables, NULL, $onlyDeleted, $this->_skipDeleteClause); // regenerate fromClause since permission might have added tables if ($this->_permissionWhereClause) { //fix for row count in qill (in contribute/membership find) if (!$count) { $this->_useDistinct = TRUE; } //CRM-15231 $this->_fromClause = self::fromClause($this->_tables, NULL, NULL, $this->_primaryLocation, $this->_mode); $this->_simpleFromClause = self::fromClause($this->_whereTables, NULL, NULL, $this->_primaryLocation, $this->_mode); // note : this modifies _fromClause and _simpleFromClause $this->includePseudoFieldsJoin($this->_sort); } } else { // add delete clause if needed even if we are skipping permission // CRM-7639 if (!$this->_skipDeleteClause) { if (CRM_Core_Permission::check('access deleted contacts') and $onlyDeleted) { $this->_permissionWhereClause = '(contact_a.is_deleted)'; } else { // CRM-6181 $this->_permissionWhereClause = '(contact_a.is_deleted = 0)'; } } } }
/** * fill the acl contact cache for this contact id if empty * * @param int $id contact id * @param string $type the type of operation (view|edit) * @param boolean $force should we force a recompute * * @return void * @access public * @static */ static function cache($userID, $type = CRM_Core_Permission::VIEW, $force = false) { static $_processed = array(); if ($type = CRM_Core_Permission::VIEW) { $operationClause = " operation IN ( 'Edit', 'View' ) "; $operation = 'View'; } else { $operationClause = " operation = 'Edit' "; $operation = 'Edit'; } if (!$force) { if (CRM_Utils_Array::value($userID, $_processed)) { return; } // run a query to see if the cache is filled $sql = "\nSELECT count(id)\nFROM civicrm_acl_contact_cache\nWHERE user_id = %1\nAND {$operationClause}\n"; $params = array(1 => array($userID, 'Integer')); $count = CRM_Core_DAO::singleValueQuery($sql, $params); if ($count > 0) { $_processed[$userID] = 1; return; } } $tables = array(); $whereTables = array(); require_once 'CRM/ACL/API.php'; $permission = CRM_ACL_API::whereClause($type, $tables, $whereTables, $userID); require_once "CRM/Contact/BAO/Query.php"; $from = CRM_Contact_BAO_Query::fromClause($whereTables); $query = "\nSELECT DISTINCT(contact_a.id) as id\n {$from}\nWHERE {$permission}\n"; $values = array(); $dao = CRM_Core_DAO::executeQuery($query); while ($dao->fetch()) { $values[] = "( {$userID}, {$dao->id}, '{$operation}' )"; } // now store this in the table while (!empty($values)) { $processed = true; $input = array_splice($values, 0, self::NUM_CONTACTS_TO_INSERT); $str = implode(',', $input); $sql = "REPLACE INTO civicrm_acl_contact_cache ( user_id, contact_id, operation ) VALUES {$str};"; CRM_Core_DAO::executeQuery($sql); } CRM_Core_DAO::executeQuery('DELETE FROM civicrm_acl_contact_cache WHERE contact_id IN (SELECT id FROM civicrm_contact WHERE is_deleted = 1)'); $_processed[$userID] = 1; return; }
/** * create and query the db for an contact search * * @param int $offset the offset for the query * @param int $rowCount the number of rows to return * @param string $sort the order by string * @param boolean $count is this a count only query ? * @param boolean $includeContactIds should we include contact ids? * @param boolean $sortByChar if true returns the distinct array of first characters for search results * @param boolean $groupContacts if true, use a single mysql group_concat statement to get the contact ids * @param boolean $returnQuery should we return the query as a string * @param string $additionalWhereClause if the caller wants to further restrict the search (used for components) * * @return CRM_Contact_DAO_Contact * @access public */ function searchQuery($offset = 0, $rowCount = 0, $sort = null, $count = false, $includeContactIds = false, $sortByChar = false, $groupContacts = false, $returnQuery = false, $additionalWhereClause = null, $sortOrder = null) { require_once 'CRM/Core/Permission.php'; if ($includeContactIds) { $this->_includeContactIds = true; $this->_whereClause = $this->whereClause(); } // hack for now, add permission only if we are in search // FIXME: we should actually filter out deleted contacts (unless requested to do the opposite) $permission = ' ( 1 ) '; $onlyDeleted = false; $onlyDeleted = in_array(array('deleted_contacts', '=', '1', '0', '0'), $this->_params); // if we’re explicitely looking for a certain contact’s contribs, events, etc. // and that contact happens to be deleted, set $onlyDeleted to true foreach ($this->_params as $values) { list($name, $op, $value, $_, $_) = $values; if ($name == 'contact_id' and $op == '=') { if (CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $value, 'is_deleted')) { $onlyDeleted = true; } break; } } if (!$this->_skipPermission) { require_once 'CRM/ACL/API.php'; $permission = CRM_ACL_API::whereClause(CRM_Core_Permission::VIEW, $this->_tables, $this->_whereTables, null, $onlyDeleted, $this->_skipDeleteClause); // CRM_Core_Error::debug( 'p', $permission ); // CRM_Core_Error::debug( 't', $this->_tables ); // CRM_Core_Error::debug( 'w', $this->_whereTables ); // regenerate fromClause since permission might have added tables if ($permission) { //fix for row count in qill (in contribute/membership find) if (!$count) { $this->_useDistinct = true; } $this->_fromClause = self::fromClause($this->_tables, null, null, $this->_primaryLocation, $this->_mode); $this->_simpleFromClause = self::fromClause($this->_whereTables, null, null, $this->_primaryLocation, $this->_mode); } } list($select, $from, $where) = $this->query($count, $sortByChar, $groupContacts); if (empty($where)) { $where = "WHERE {$permission}"; } else { $where = "{$where} AND {$permission}"; } // CRM_Core_Error::debug( 't', $this ); // CRM_Core_Error::debug( 'w', $where ); // CRM_Core_Error::debug( 'a', $additionalWhereClause ); if ($additionalWhereClause) { $where = $where . ' AND ' . $additionalWhereClause; } $order = $orderBy = $limit = ''; if (!$count) { $config = CRM_Core_Config::singleton(); if ($config->includeOrderByClause) { if ($sort) { if (is_string($sort)) { $orderBy = $sort; } else { $orderBy = trim($sort->orderBy()); } if (!empty($orderBy)) { // this is special case while searching for // changelog CRM-1718 if (preg_match('/sort_name/i', $orderBy)) { $orderBy = str_replace('sort_name', 'contact_a.sort_name', $orderBy); } $order = " ORDER BY {$orderBy}"; if ($sortOrder) { $order .= " {$sortOrder}"; } } } else { if ($sortByChar) { $orderBy = " ORDER BY LEFT(contact_a.sort_name, 1) asc"; } else { $orderBy = " ORDER BY contact_a.sort_name asc"; } } } if ($rowCount > 0 && $offset >= 0) { $limit = " LIMIT {$offset}, {$rowCount} "; // ok here is a first hack at an optimization, lets get all the contact ids // that are restricted and we'll then do the final clause with it // CRM-5954 $limitSelect = $this->_useDistinct ? 'SELECT DISTINCT(contact_a.id) as id' : 'SELECT contact_a.id as id'; $doOpt = true; // hack for order clause if ($orderBy) { $fieldOrder = explode(' ', $orderBy); $field = $fieldOrder[0]; $dir = CRM_Utils_Array::value(1, $fieldOrder); if ($field) { switch ($field) { case 'sort_name': break; case 'city': case 'postal_code': $this->_whereTables["civicrm_address"] = 1; $limitSelect .= ", civicrm_address.{$field} as {$field}"; break; case 'country': case 'state_province': $this->_whereTables["civicrm_{$field}"] = 1; $limitSelect .= ", civicrm_{$field}.name as {$field}"; break; case 'email': $this->_whereTables["civicrm_email"] = 1; $limitSelect .= ", civicrm_email.email as email"; break; default: $doOpt = false; } } } if ($doOpt) { $this->_simpleFromClause = self::fromClause($this->_whereTables, null, null, $this->_primaryLocation, $this->_mode); $limitQuery = "{$limitSelect} {$this->_simpleFromClause} {$where} {$order} {$limit}"; $limitDAO = CRM_Core_DAO::executeQuery($limitQuery); $limitIDs = array(); while ($limitDAO->fetch()) { $limitIDs[] = $limitDAO->id; } if (empty($limitIDs)) { $limitClause = ' AND ( 0 ) '; } else { $limitClause = ' AND contact_a.id IN ( ' . implode(',', $limitIDs) . ' ) '; } $where .= $limitClause; // reset limit clause since we already restrict what records we want $limit = null; } } } // building the query string $groupBy = null; if (!$count) { if (isset($this->_groupByComponentClause)) { $groupBy = $this->_groupByComponentClause; } else { if ($this->_useGroupBy) { $groupBy = ' GROUP BY contact_a.id'; } } } if ($this->_mode & CRM_Contact_BAO_Query::MODE_ACTIVITY && !$count) { $groupBy = 'GROUP BY civicrm_activity.id '; } $query = "{$select} {$from} {$where} {$groupBy} {$order} {$limit}"; // CRM_Core_Error::debug('query', $query); // CRM_Core_Error::debug('query', $where); if ($returnQuery) { return $query; } if ($count) { return CRM_Core_DAO::singleValueQuery($query); } $dao =& CRM_Core_DAO::executeQuery($query); if ($groupContacts) { $ids = array(); while ($dao->fetch()) { $ids[] = $dao->id; } return implode(',', $ids); } return $dao; }
/** * create and query the db for an contact search * * @param int $offset the offset for the query * @param int $rowCount the number of rows to return * @param string $sort the order by string * @param boolean $count is this a count only query ? * @param boolean $includeContactIds should we include contact ids? * @param boolean $sortByChar if true returns the distinct array of first characters for search results * @param boolean $groupContacts if true, use a single mysql group_concat statement to get the contact ids * @param boolean $returnQuery should we return the query as a string * @param string $additionalWhereClause if the caller wants to further restrict the search (used for components) * * @return CRM_Contact_DAO_Contact * @access public */ function searchQuery($offset = 0, $rowCount = 0, $sort = null, $count = false, $includeContactIds = false, $sortByChar = false, $groupContacts = false, $returnQuery = false, $additionalWhereClause = null) { require_once 'CRM/Core/Permission.php'; if ($includeContactIds) { $this->_includeContactIds = true; $this->_whereClause = $this->whereClause(); } // hack for now, add permission only if we are in search $permission = ' ( 1 ) '; if (!$this->_skipPermission) { require_once 'CRM/ACL/API.php'; $permission = CRM_ACL_API::whereClause(CRM_Core_Permission::VIEW, $this->_tables, $this->_whereTables); // CRM_Core_Error::debug( 'p', $permission ); // CRM_Core_Error::debug( 't', $this->_tables ); // CRM_Core_Error::debug( 'w', $this->_whereTables ); // regenerate fromClause since permission might have added tables if ($permission) { //fix for row count in qill (in contribute/membership find) if (!$count) { $this->_useDistinct = true; } $this->_fromClause = self::fromClause($this->_tables, null, null, $this->_primaryLocation, $this->_mode); $this->_simpleFromClause = self::fromClause($this->_whereTables, null, null, $this->_primaryLocation, $this->_mode); } } list($select, $from, $where) = $this->query($count, $sortByChar, $groupContacts); if (empty($where)) { $where = "WHERE {$permission}"; } else { $where = "{$where} AND {$permission}"; } if ($additionalWhereClause) { $where = $where . ' AND ' . $additionalWhereClause; } $order = $orderBy = $limit = ''; if (!$count) { $config =& CRM_Core_Config::singleton(); if ($config->includeOrderByClause) { if ($sort) { if (is_string($sort)) { $orderBy = $sort; } else { $orderBy = trim($sort->orderBy()); } if (!empty($orderBy)) { // this is special case while searching for // changelog CRM-1718 if (preg_match('/sort_name/i', $orderBy)) { $orderBy = str_replace('sort_name', 'contact_a.sort_name', $orderBy); } $order = " ORDER BY {$orderBy}"; } } else { if ($sortByChar) { $orderBy = " ORDER BY LEFT(contact_a.sort_name, 1) asc"; } else { $orderBy = " ORDER BY contact_a.sort_name asc"; } } } if ($rowCount > 0 && $offset >= 0) { $limit = " LIMIT {$offset}, {$rowCount} "; // ok here is a first hack at an optimization, lets get all the contact ids // that are restricted and we'll then do the final clause with it $limitSelect = $this->_useDistinct ? 'SELECT DISTINCT(contact_a.id) as id' : 'SELECT contact_a.id as id'; $doOpt = true; // hack for order clause if ($orderBy) { list($field, $dir) = split(' ', $orderBy); if ($field) { switch ($field) { case 'sort_name': break; case 'city': case 'postal_code': $this->_whereTables["civicrm_address"] = 1; $limitSelect .= ", civicrm_address.{$field} as {$field}"; break; case 'country': case 'state_province': $this->_whereTables["civicrm_{$field}"] = 1; $limitSelect .= ", civicrm_{$field}.name as {$field}"; break; case 'email': $this->_whereTables["civicrm_email"] = 1; $limitSelect .= ", civicrm_email.email as email"; break; default: $doOpt = false; } } } if ($doOpt) { $this->_simpleFromClause = self::fromClause($this->_whereTables, null, null, $this->_primaryLocation, $this->_mode); $limitQuery = "{$limitSelect} {$this->_simpleFromClause} {$where} {$order} {$limit}"; $limitDAO = CRM_Core_DAO::executeQuery($limitQuery); $limitIDs = array(); while ($limitDAO->fetch()) { $limitIDs[] = $limitDAO->id; } if (empty($limitIDs)) { $limitClause = ' AND ( 0 ) '; } else { $limitClause = ' AND contact_a.id IN ( ' . implode(',', $limitIDs) . ' ) '; } $where .= $limitClause; // reset limit clause since we already restrict what records we want $limit = null; } } } // building the query string $groupBy = null; if (!$count) { if (isset($this->_groupByComponentClause)) { $groupBy = $this->_groupByComponentClause; } else { if ($this->_useGroupBy) { $groupBy = ' GROUP BY contact_a.id'; } } } $query = "{$select} {$from} {$where} {$groupBy} {$order} {$limit}"; //CRM_Core_Error::debug('query', $query); exit(); if ($returnQuery) { return $query; } if ($count) { return CRM_Core_DAO::singleValueQuery($query, CRM_Core_DAO::$_nullArray); } $dao =& CRM_Core_DAO::executeQuery($query); if ($groupContacts) { $ids = array(); while ($dao->fetch()) { $ids[] = $dao->id; } return implode(',', $ids); } return $dao; }