Esempio n. 1
0
 /**
  * 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;
 }
Esempio n. 3
0
 /**
  * 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)';
             }
         }
     }
 }
Esempio n. 4
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;
 }
Esempio n. 5
0
 /**
  * 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;
 }
Esempio n. 6
0
 /**
  * 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;
 }