* so we can skip the other
*/
protected $_rangeCache = array();
-
+/**
+ * Set to true when $this->relationship is run to avoid adding twice
+ * @var Boolean
+ */
+ protected $_relationshipValuesAdded = FALSE;
/**
* class constructor which also does all the work
*
// add activity fields
$fields = CRM_Activity_BAO_Activity::exportableFields();
$this->_fields = array_merge($this->_fields, $fields);
+
+ // add any fields provided by hook implementers
+ $extFields = CRM_Contact_BAO_Query_Hook::singleton()->getFields();
+ $this->_fields = array_merge($this->_fields, $extFields);
}
// basically do all the work once, and then reuse it
* @access public
*/
function selectClause() {
- $properties = array();
$this->addSpecialFields();
foreach ($this->_fields as $name => $field) {
-
// skip component fields
// there are done by the alter query below
// and need not be done on every field
continue;
}
+ // make an exception for special cases, to add the field in select clause
+ $makeException = FALSE;
+
+ //special handling for groups/tags
+ if (in_array($name, array('groups', 'tags', 'notes'))
+ && isset($this->_returnProperties[substr($name, 0, -1)])
+ ) {
+ $makeException = TRUE;
+ }
+
+ // since note has 3 different options we need special handling
+ // note / note_subject / note_body
+ if ($name == 'notes') {
+ foreach (array('note', 'note_subject', 'note_body') as $noteField) {
+ if (isset($this->_returnProperties[$noteField])) {
+ $makeException = TRUE;
+ break;
+ }
+ }
+ }
+
$cfID = CRM_Core_BAO_CustomField::getKeyID($name);
if (
CRM_Utils_Array::value($name, $this->_paramLookup) ||
- CRM_Utils_Array::value($name, $this->_returnProperties)
+ CRM_Utils_Array::value($name, $this->_returnProperties) ||
+ $makeException
) {
if ($cfID) {
// add to cfIDs array if not present
//fix for CRM-951
CRM_Core_Component::alterQuery($this, 'select');
+ CRM_Contact_BAO_Query_Hook::singleton()->alterSearchQuery($this, 'select');
+
if (!empty($this->_cfIDs)) {
$this->_customQuery = new CRM_Core_BAO_CustomQuery($this->_cfIDs, TRUE);
$this->_customQuery->query();
if (($elementName != 'phone') && ($elementName != 'im')) {
$cond = self::getPrimaryCondition($elementType);
}
- if ((!$cond) && ($elementName == 'phone')) {
+ // CRM-13011 : If location type is primary, do not restrict search to the phone
+ // type id - we want the primary phone, regardless of what type it is.
+ // Otherwise, restrict to the specified phone type for the given field.
+ if ((!$cond) && ($elementName == 'phone') && $elements['location_type'] != 'Primary') {
$cond = "phone_type_id = '$elementType'";
}
elseif ((!$cond) && ($elementName == 'im')) {
$this->filterRelatedContacts($from, $where, $having);
}
- // CRM_Core_Error::debug($this);
return array($select, $from, $where, $having);
}
function &getWhereValues($name, $grouping) {
$result = NULL;
- foreach ($this->_params as $id => $values) {
+ foreach ($this->_params as $values) {
if ($values[0] == $name && $values[3] == $grouping) {
return $values;
}
return;
}
+ // skip for hook injected fields / params
+ $extFields = CRM_Contact_BAO_Query_Hook::singleton()->getFields();
+ if (array_key_exists($values[0], $extFields)) {
+ return;
+ }
+
switch ($values[0]) {
case 'deleted_contacts':
$this->deletedContacts($values);
return;
case 'relation_type_id':
+ case 'relation_start_date_high':
+ case 'relation_start_date_low':
+ case 'relation_end_date_high':
+ case 'relation_end_date_low':
$this->relationship($values);
+ $this->_relationshipValuesAdded = TRUE;
return;
case 'relation_target_name':
}
CRM_Core_Component::alterQuery($this, 'where');
+
+ CRM_Contact_BAO_Query_Hook::singleton()->alterSearchQuery($this, 'where');
}
if ($this->_customQuery) {
$this->_qill[$grouping][] = ts('State') . " ($lType) $op '$value'";
}
}
- elseif ($field['pseudoconstant']) {
+ elseif (!empty($field['pseudoconstant'])) {
$this->optionValueQuery(
$name, $op, $value, $grouping,
CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', $field['name']),
// to handle table dependencies of components
CRM_Core_Component::tableNames($tables);
+ // to handle table dependencies of hook injected tables
+ CRM_Contact_BAO_Query_Hook::singleton()->setTableDependency($tables);
//format the table list according to the weight
$info = CRM_Core_TableHierarchy::info();
default:
$from .= CRM_Core_Component::from($name, $mode, $side);
+ $from .= CRM_Contact_BAO_Query_Hook::singleton()->buildSearchfrom($name, $mode, $side);
+
continue;
}
}
// search tag in activities
$etActTable = "`civicrm_entity_act_tag-" . $value . "`";
$tActTable = "`civicrm_act_tag-" . $value . "`";
- $activityContacts = CRM_Core_PseudoConstant::activityContacts('name');
+ $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
$targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
$this->_tables[$etActTable] =
function tag(&$values) {
list($name, $op, $value, $grouping, $wildcard) = $values;
- $tagNames = CRM_Core_PseudoConstant::tag();
+ $tagNames = CRM_Core_PseudoConstant::get('CRM_Core_DAO_EntityTag', 'tag_id', array('onlyActive' => FALSE));
if (is_array($value)) {
if (count($value) > 1) {
$this->_useDistinct = TRUE;
// search tag in cases
$etCaseTable = "`civicrm_entity_case_tag-" . $value . "`";
- $activityContacts = CRM_Core_PseudoConstant::activityContacts('name');
+ $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
$targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
$this->_tables[$etCaseTable] =
$this->_qill[$grouping][] = ts('State/Province') . " $op " . implode(' ' . ts('or') . ' ', $names) . $countryQill;
}
else {
- return implode(' ' . ts('or') . ' ', $names) . $countryQill;;
+ return implode(' ' . ts('or') . ' ', $names) . $countryQill;
}
}
function privacyOptions($values) {
list($name, $op, $value, $grouping, $wildcard) = $values;
- if (empty($value) ||
- !is_array($value)
- ) {
- continue;
+ if (empty($value) || !is_array($value)) {
+ return;
}
// get the operator and toggle values
}
}
- $commPref = CRM_Core_PseudoConstant::pcm();
+ $commPref = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'preferred_communication_method');
$sqlValue = array();
$sql = "contact_a.preferred_communication_method";
*/
function relationship(&$values) {
list($name, $op, $value, $grouping, $wildcard) = $values;
-
+ if($this->_relationshipValuesAdded){
+ return;
+ }
// also get values array for relation_target_name
// for relatinship search we always do wildcard
$targetName = $this->getWhereValues('relation_target_name', $grouping);
$relStatus = $this->getWhereValues('relation_status', $grouping);
$targetGroup = $this->getWhereValues('relation_target_group', $grouping);
- $start = $this->getWhereValues('relation_date_low', $grouping);
- $end = $this->getWhereValues('relation_date_high', $grouping);
$nameClause = $name = NULL;
if ($targetName) {
$rel = explode('_', $value);
self::$_relType = $rel[1];
-
- $params = array('id' => $rel[0]);
- $rTypeValues = array();
- $rType = CRM_Contact_BAO_RelationshipType::retrieve($params, $rTypeValues);
- if (!$rType) {
- return;
- }
-
- if ($rTypeValues['name_a_b'] == $rTypeValues['name_b_a']) {
- self::$_relType = 'reciprocal';
- }
+ $params = array('id' => $rel[0]);
+ $rTypeValues = array();
+ $rType = CRM_Contact_BAO_RelationshipType::retrieve($params, $rTypeValues);
+ if ($rTypeValues['name_a_b'] == $rTypeValues['name_b_a']) {
+ self::$_relType = 'reciprocal';
+ }
if ($nameClause) {
$this->_where[$grouping][] = "( contact_b.sort_name $nameClause AND contact_b.id != contact_a.id )";
$this->_qill[$grouping][] = ts('Relationship - Inactive or not Current');
}
- // Search by dates
- if ($start || $end) {
- foreach (array('start' => '>=', 'end' => '<=') as $d => $op) {
- if (!empty(${$d}[2])) {
- $date = date('Ymd', strtotime(${$d}[2]));
- $this->_where[$grouping][] = "civicrm_relationship.{$d}_date $op $date";
- $this->_qill[$grouping][] = ($d == 'end' ? ts('Relationship Ended by') : ts('Relationship Started On or After')) . " " . CRM_Utils_Date::customFormat($date);
- }
- }
+ $this->addRelationshipDateClauses($grouping);
+ if(!empty($rType) && isset($rType->id)){
+ $this->_where[$grouping][] = 'civicrm_relationship.relationship_type_id = ' . $rType->id;
}
-
- $this->_where[$grouping][] = 'civicrm_relationship.relationship_type_id = ' . $rel[0];
$this->_tables['civicrm_relationship'] = $this->_whereTables['civicrm_relationship'] = 1;
$this->_useDistinct = TRUE;
+ $this->_relationshipValuesAdded = TRUE;
}
+/**
+ * Add start & end date criteria in
+ * @param string $grouping
+ */
+ function addRelationshipDateClauses($grouping){
+ $dateValues = array();
+ $dateTypes = array(
+ 'start_date',
+ 'end_date',
+ );
+ foreach ($dateTypes as $dateField){
+ $dateValueLow = $this->getWhereValues('relation_'. $dateField .'_low', $grouping);
+ $dateValueHigh= $this->getWhereValues('relation_'. $dateField .'_high', $grouping);
+ if(!empty($dateValueLow)){
+ $date = date('Ymd', strtotime($dateValueLow[2]));
+ $this->_where[$grouping][] = "civicrm_relationship.$dateField >= $date";
+ $this->_qill[$grouping][] = ($dateField == 'end_date' ? ts('Relationship Ended on or After') : ts('Relationship Recorded Start Date On or Before')) . " " . CRM_Utils_Date::customFormat($date);
+ }
+ if(!empty($dateValueHigh)){
+ $date = date('Ymd', strtotime($dateValueHigh[2]));
+ $this->_where[$grouping][] = "civicrm_relationship.$dateField <= $date";
+ $this->_qill[$grouping][] = ( $dateField == 'end_date' ? ts('Relationship Ended on or Before') : ts('Relationship Recorded Start Date On or After')) . " " . CRM_Utils_Date::customFormat($date);
+ }
+ }
+ }
/**
* default set of return properties
*
$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.
+ // if we’re explicitly 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) {
$name = CRM_Utils_Array::value(0, $values);
}
$this->generatePermissionClause($onlyDeleted, $count);
- 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 $this->_permissionWhereClause";
}
}
}
- $doOpt = TRUE;
// hack for order clause
if ($order) {
$fieldStr = trim(str_replace('ORDER BY', '', $order));
$this->_whereTables["civicrm_email"] = 1;
$order = str_replace($field, "civicrm_email.{$field}", $order);
break;
-
- default:
- $doOpt = FALSE;
}
+ $this->_fromClause = self::fromClause($this->_tables, NULL, NULL, $this->_primaryLocation, $this->_mode);
+ $this->_simpleFromClause = self::fromClause($this->_whereTables, NULL, NULL, $this->_primaryLocation, $this->_mode);
}
}
-
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);
- }
+ list($select, $from, $where, $having) = $this->query($count, $sortByChar, $groupContacts);
- $limitQuery = "$limitSelect {$this->_simpleFromClause} $where $groupBy $order $limit";
- $limitDAO = CRM_Core_DAO::executeQuery($limitQuery);
- $limitIDs = array();
- while ($limitDAO->fetch()) {
- if ($limitDAO->id) {
- $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;
- }
- }
+ //additional from clause should be w/ proper joins.
+ if ($additionalFromClause) {
+ $from .= "\n" . $additionalFromClause;
}
// if we are doing a transform, do it here
return CRM_Core_DAO::singleValueQuery($query);
}
- // crm_core_error::debug('$query', $query); exit;
-
$dao = CRM_Core_DAO::executeQuery($query);
if ($groupContacts) {
$ids = array();
return $dao;
}
+ /**
+ * Fetch a list of contacts from the prev/next cache for displaying a search results page
+ *
+ * @param string $cacheKey
+ * @param int $offset
+ * @param int $rowCount
+ * @param bool $includeContactIds
+ * @return CRM_Core_DAO
+ */
+ function getCachedContacts($cacheKey, $offset, $rowCount, $includeContactIds) {
+ $this->_includeContactIds = $includeContactIds;
+ list($select, $from) = $this->query();
+ $from = " FROM civicrm_prevnext_cache pnc INNER JOIN civicrm_contact contact_a ON contact_a.id = pnc.entity_id1 AND pnc.cacheKey = '$cacheKey' " . substr($from, 31);
+ $order = " ORDER BY pnc.id";
+ $groupBy = " GROUP BY contact_a.id";
+ $limit = " LIMIT $offset, $rowCount";
+ $query = "$select $from $groupBy $order $limit";
+ return CRM_Core_DAO::executeQuery($query);
+ }
+
/**
* Populate $this->_permissionWhereClause with permission related clause and update other
* query related properties.