From 3130209f58efcbec0b80076506c1c1d0ab2ba671 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Mon, 4 Aug 2014 22:07:59 +0100 Subject: [PATCH] CRM-15061 - Standardize custom field options search widget to always be multiselect --- CRM/Contact/BAO/Query.php | 7 + CRM/Core/BAO/CustomField.php | 198 +++++++++----------------- CRM/Core/BAO/CustomQuery.php | 177 +++++++++-------------- CRM/Profile/Page/Listings.php | 12 +- templates/CRM/Custom/Form/Search.tpl | 42 +----- templates/CRM/Profile/Form/Search.tpl | 45 +----- 6 files changed, 162 insertions(+), 319 deletions(-) diff --git a/CRM/Contact/BAO/Query.php b/CRM/Contact/BAO/Query.php index 681142af20..0c7df5514f 100644 --- a/CRM/Contact/BAO/Query.php +++ b/CRM/Contact/BAO/Query.php @@ -563,6 +563,13 @@ class CRM_Contact_BAO_Query { if (!array_key_exists($cfID, $this->_cfIDs)) { $this->_cfIDs[$cfID] = array(); } + // Set wildcard value based on "and/or" selection + foreach ($this->_params as $key => $param) { + if ($param[0] == $value[0] . '_operator') { + $value[4] = $param[2] == 'or'; + break; + } + } $this->_cfIDs[$cfID][] = $value; } diff --git a/CRM/Core/BAO/CustomField.php b/CRM/Core/BAO/CustomField.php index 3336e02f20..102ac39085 100644 --- a/CRM/Core/BAO/CustomField.php +++ b/CRM/Core/BAO/CustomField.php @@ -726,7 +726,7 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { * @param CRM_Core_Form $qf form object (reference) * @param string $elementName name of the custom field * @param $fieldId - * @param boolean $inactiveNeeded + * @param boolean $inactiveNeeded -deprecated * @param bool $useRequired * @param boolean $search true if used for search else false * @param string $label label for custom field @@ -744,6 +744,7 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { $label = NULL ) { $field = self::getFieldObject($fieldId); + $widget = $field->html_type; // Custom field HTML should indicate group+field name $groupName = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $field->custom_group_id); @@ -752,29 +753,44 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { $field->attributes .= $dataCrmCustomAttr; // Fixed for Issue CRM-2183 - if ($field->html_type == 'TextArea' && $search) { - $field->html_type = 'Text'; + if ($widget == 'TextArea' && $search) { + $widget = 'Text'; + } + + if ($widget == 'Select State/Province' || $widget == 'Select Country') { + $qf->_stateCountryMap[$widget == 'Select Country' ? 'country' : 'state_province'][] = $elementName; } $placeholder = $search ? ts('- any -') : ($useRequired ? ts('- select -') : ts('- none -')); // FIXME: Why are select state/country separate widget types? - if (in_array($field->html_type, array('Select', 'Multi-Select', 'Select State/Province', 'Multi-Select State/Province', 'Select Country', 'Multi-Select Country'))) { + $isSelect = (in_array($widget, array('Select', 'Multi-Select', 'Select State/Province', 'Multi-Select State/Province', 'Select Country', 'Multi-Select Country', 'AdvMulti-Select', 'CheckBox', 'Radio'))); + + if ($isSelect) { + $options = CRM_Utils_Array::value('values', civicrm_api3('contact', 'getoptions', array('field' => "custom_$fieldId", 'context' => $search ? 'search' : 'create'), array())); + + // Consolidate widget types to simplify the below switch statement + if ($search || ($widget !== 'AdvMulti-Select' && strpos($widget, 'Select') !== FALSE)) { + $widget = 'Select'; + } $selectAttributes = array( 'data-crm-custom' => $dataCrmCustomVal, 'class' => 'crm-select2', ); - if (strpos($field->html_type, 'Multi') === 0) { + // Search field is always multi-select + if ($search || strpos($field->html_type, 'Multi') !== FALSE) { + $selectAttributes['class'] .= ' huge'; $selectAttributes['multiple'] = 'multiple'; + $selectAttributes['placeholder'] = $placeholder; + } + // Add data for popup link. Normally this is handled by CRM_Core_Form->addSelect + if ($field->option_group_id && !$search && $widget == 'Select' && CRM_Core_Permission::check('administer CiviCRM')) { + $selectAttributes += array( + 'data-api-entity' => 'contact', // FIXME: This works because the getoptions api isn't picky about custom fields, but it's WRONG + 'data-api-field' => 'custom_' . $field->id, + 'data-option-edit-path' => 'civicrm/admin/options/' . CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $field->option_group_id), + ); } - } - // Add data so popup link. Normally this is handled by CRM_Core_Form->addSelect - if ($field->option_group_id && !$search && in_array($field->html_type, array('Select', 'Multi-Select')) && CRM_Core_Permission::check('administer CiviCRM')) { - $selectAttributes += array( - 'data-api-entity' => 'contact', // FIXME: This works because the getoptions api isn't picky about custom fields, but it's WRONG - 'data-api-field' => 'custom_' . $field->id, - 'data-option-edit-path' => 'civicrm/admin/options/' . CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $field->option_group_id), - ); } if (!isset($label)) { @@ -785,14 +801,15 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { * at some point in time we might want to split the below into small functions **/ - switch ($field->html_type) { + switch ($widget) { case 'Text': + case 'Link': if ($field->is_search_range && $search) { $qf->add('text', $elementName . '_from', $label . ' ' . ts('From'), $field->attributes); $qf->add('text', $elementName . '_to', ts('To'), $field->attributes); } else { - $element = &$qf->add(strtolower($field->html_type), $elementName, $label, + $element = &$qf->add('text', $elementName, $label, $field->attributes, $useRequired && !$search ); @@ -816,7 +833,7 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { if ($field->text_length) { $attributes .= ' maxlength=' . $field->text_length; } - $element = &$qf->add(strtolower($field->html_type), + $element = &$qf->add('textarea', $elementName, $label, $attributes, @@ -861,20 +878,10 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { case 'Radio': $choice = array(); - if ($field->data_type != 'Boolean') { - $customOption = CRM_Core_BAO_CustomOption::valuesByID($field->id, - $field->option_group_id - ); - foreach ($customOption as $v => $l) { - $choice[] = $qf->createElement('radio', NULL, '', $l, (string)$v, $field->attributes); - } - $group = $qf->addGroup($choice, $elementName, $label); - } - else { - $choice[] = $qf->createElement('radio', NULL, '', ts('Yes'), '1', $field->attributes); - $choice[] = $qf->createElement('radio', NULL, '', ts('No'), '0', $field->attributes); - $group = $qf->addGroup($choice, $elementName, $label); + foreach ($options as $v => $l) { + $choice[] = $qf->createElement('radio', NULL, '', $l, (string)$v, $field->attributes); } + $group = $qf->addGroup($choice, $elementName, $label); if ($useRequired && !$search) { $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required'); } @@ -883,34 +890,30 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { } break; + // For all select elements case 'Select': - $selectOption = CRM_Core_BAO_CustomOption::valuesByID($field->id, - $field->option_group_id - ); - - $qf->add('select', $elementName, $label, - array('' => $placeholder) + $selectOption, - $useRequired && !$search, - $selectAttributes - ); - break; + if (empty($selectAttributes['multiple'])) { + $options = array('' => $placeholder) + $options; + } + $qf->add('select', $elementName, $label, $options, $useRequired && !$search, $selectAttributes); - //added for select multiple + // Add and/or option for fields that store multiple values + if ($search && self::isSerialized($field)) { - case 'AdvMulti-Select': - $selectOption = CRM_Core_BAO_CustomOption::valuesByID($field->id, - $field->option_group_id - ); - if ($search && - count($selectOption) > 1 - ) { - $selectOption['CiviCRM_OP_OR'] = ts('Select to match ANY; unselect to match ALL'); + $operators = array( + $qf->createElement('radio', NULL, '', ts('Any'), 'or', array('title' => ts('Results may contain any of the selected options'))), + $qf->createElement('radio', NULL, '', ts('All'), 'and', array('title' => ts('Results must have all of the selected options'))), + ); + $qf->addGroup($operators, $elementName . '_operator'); + $qf->setDefaults(array($elementName . '_operator' => 'or')); } + break; + case 'AdvMulti-Select': $include =& $qf->addElement( 'advmultiselect', $elementName, - $label, $selectOption, + $label, $options, array( 'size' => 5, 'style' => '', @@ -927,35 +930,11 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { } break; - case 'Multi-Select': - $selectOption = CRM_Core_BAO_CustomOption::valuesByID($field->id, - $field->option_group_id - ); - if ($search && - count($selectOption) > 1 - ) { - $selectOption['CiviCRM_OP_OR'] = ts('Select to match ANY; unselect to match ALL'); - } - $qf->addElement('select', $elementName, $label, $selectOption, $selectAttributes); - - if ($useRequired && !$search) { - $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required'); - } - break; - case 'CheckBox': - $customOption = CRM_Core_BAO_CustomOption::valuesByID($field->id, - $field->option_group_id - ); $check = array(); - foreach ($customOption as $v => $l) { + foreach ($options as $v => $l) { $check[] = &$qf->addElement('advcheckbox', $v, NULL, $l, array('data-crm-custom' => $dataCrmCustomVal)); } - if ($search && - count($check) > 1 - ) { - $check[] = &$qf->addElement('advcheckbox', 'CiviCRM_OP_OR', NULL, ts('Check to match ANY; uncheck to match ALL'), array('data-crm-custom' => $dataCrmCustomVal)); - } $qf->addGroup($check, $elementName, $label); if ($useRequired && !$search) { $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required'); @@ -977,45 +956,6 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { $qf->addUploadElement($elementName); break; - case 'Select State/Province': - //Add State - $stateOption = array('' => $placeholder) + CRM_Core_PseudoConstant::stateProvince(); - $qf->add('select', $elementName, $label, $stateOption, - $useRequired && !$search, - $selectAttributes - ); - $qf->_stateCountryMap['state_province'][] = $elementName; - break; - - case 'Multi-Select State/Province': - //Add Multi-select State/Province - $stateOption = CRM_Core_PseudoConstant::stateProvince(); - - $qf->addElement('select', $elementName, $label, $stateOption, $selectAttributes); - if ($useRequired && !$search) { - $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required'); - } - break; - - case 'Select Country': - //Add Country - $countryOption = array('' => $placeholder) + CRM_Core_PseudoConstant::country(); - $qf->add('select', $elementName, $label, $countryOption, - $useRequired && !$search, - $selectAttributes - ); - $qf->_stateCountryMap['country'][] = $elementName; - break; - - case 'Multi-Select Country': - //Add Country - $countryOption = CRM_Core_PseudoConstant::country(); - $qf->addElement('select', $elementName, $label, $countryOption, $selectAttributes); - if ($useRequired && !$search) { - $qf->addRule($elementName, ts('%1 is a required field.', array(1 => $label)), 'required'); - } - break; - case 'RichTextEditor': $attributes = array('rows' => $field->note_rows, 'cols' => $field->note_columns, 'data-crm-custom' => $dataCrmCustomVal); if ($field->text_length) { @@ -1074,7 +1014,7 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { $qf->addRule($elementName . '_from', ts('%1 From must be an integer (whole number).', array(1 => $label)), 'integer'); $qf->addRule($elementName . '_to', ts('%1 To must be an integer (whole number).', array(1 => $label)), 'integer'); } - else { + elseif ($widget == 'Text') { $qf->addRule($elementName, ts('%1 must be an integer (whole number).', array(1 => $label)), 'integer'); } break; @@ -1084,7 +1024,7 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { $qf->addRule($elementName . '_from', ts('%1 From must be a number (with or without decimal point).', array(1 => $label)), 'numeric'); $qf->addRule($elementName . '_to', ts('%1 To must be a number (with or without decimal point).', array(1 => $label)), 'numeric'); } - else { + elseif ($widget == 'Text') { $qf->addRule($elementName, ts('%1 must be a number (with or without decimal point).', array(1 => $label)), 'numeric'); } break; @@ -1094,23 +1034,15 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField { $qf->addRule($elementName . '_from', ts('%1 From must in proper money format. (decimal point/comma/space is allowed).', array(1 => $label)), 'money'); $qf->addRule($elementName . '_to', ts('%1 To must in proper money format. (decimal point/comma/space is allowed).', array(1 => $label)), 'money'); } - else { + elseif ($widget == 'Text') { $qf->addRule($elementName, ts('%1 must be in proper money format. (decimal point/comma/space is allowed).', array(1 => $label)), 'money'); } break; case 'Link': - $qf->add( - 'text', - $elementName, - $label, - array( - 'onfocus' => "if (!this.value) { this.value='http://';} else return false", - 'onblur' => "if ( this.value == 'http://') { this.value='';} else return false", - 'data-crm-custom' => $dataCrmCustomVal, - ), - $useRequired && !$search - ); + $element->setAttribute('onfocus', "if (!this.value) {this.value='http://';}"); + $element->setAttribute('onblur', "if (this.value == 'http://') {this.value='';}"); + $element->setAttribute('class', "url"); $qf->addRule($elementName, ts('Enter a valid Website.'), 'wikiURL'); break; } @@ -2552,5 +2484,17 @@ WHERE cf.id = %1 AND cg.is_multiple = 1"; return $isMultipleWithGid; } + + /** + * Does this field store a serialized string? + * @param CRM_Core_DAO_CustomField|array $field + * @return bool + */ + static function isSerialized($field) { + // Fields retrieved via api are an array, or from the dao are an object. We'll accept either. + $field = (array) $field; + // FIXME: Currently the only way to know if data is serialized is by looking at the html_type. It would be cleaner to decouple this. + return ($field['html_type'] == 'CheckBox' || strpos($field['html_type'], 'Multi') !== FALSE); + } } diff --git a/CRM/Core/BAO/CustomQuery.php b/CRM/Core/BAO/CustomQuery.php index 6a36b4468d..9d6e64a561 100644 --- a/CRM/Core/BAO/CustomQuery.php +++ b/CRM/Core/BAO/CustomQuery.php @@ -347,101 +347,81 @@ SELECT label, value foreach ($values as $tuple) { list($name, $op, $value, $grouping, $wildcard) = $tuple; - // fix $value here to escape sql injection attacks $field = $this->_fields[$id]; - $qillValue = CRM_Core_BAO_CustomField::getDisplayValue($value, $id, $this->_options); - if (!is_array($value)) { - $value = CRM_Core_DAO::escapeString(trim($value)); + $fieldName = "{$field['table_name']}.{$field['column_name']}"; + + // Handle multi-select search for any data type + if (is_array($value) && !$field['is_search_range']) { + $isSerialized = CRM_Core_BAO_CustomField::isSerialized($field); + $wildcard = $isSerialized ? $wildcard : TRUE; + $options = CRM_Utils_Array::value('values', civicrm_api3('contact', 'getoptions', array('field' => $name, 'context' => 'search'), array())); + $qillValue = ''; + $sqlOP = $wildcard ? ' OR ' : ' AND '; + $sqlValue = array(); + foreach ($value as $num => &$v) { + $sep = count($value) > (1 + $num) ? ', ' : (' ' . ($wildcard ? ts('OR') : ts('AND')) . ' '); + $qillValue .= ($num ? $sep : '') . $options[$v]; + $v = CRM_Core_DAO::escapeString($v); + if ($isSerialized) { + $sqlValue[] = "( $fieldName like '%" . CRM_Core_DAO::VALUE_SEPARATOR . $v . CRM_Core_DAO::VALUE_SEPARATOR . "%' ) "; + } + else { + $v = "'$v'"; + } + } + if (!$isSerialized) { + $sqlValue = array("$fieldName IN (" . implode(',', $value) . ")"); + } + $this->_where[$grouping][] = ' ( ' . implode($sqlOP, $sqlValue) . ' ) '; + $this->_qill[$grouping][] = "$field[label] $op $qillValue"; + continue; } - $fieldName = "{$field['table_name']}.{$field['column_name']}"; + // fix $value here to escape sql injection attacks + $value = CRM_Core_DAO::escapeString(trim($value)); + + $qillValue = CRM_Core_BAO_CustomField::getDisplayValue($value, $id, $this->_options); + switch ($field['data_type']) { case 'String': $sql = "$fieldName"; - // if we are coming in from listings, - // for checkboxes the value is already in the right format and is NOT an array - if (is_array($value)) { - - //ignoring $op value for checkbox and multi select - $sqlValue = array(); - $sqlOP = ' AND '; - $sqlOPlabel = ts('match ALL'); - if ($field['html_type'] == 'CheckBox') { - foreach ($value as $k => $v) { - if ($v) { - if ($k == 'CiviCRM_OP_OR') { - $sqlOP = ' OR '; - $sqlOPlabel = ts('match ANY'); - continue; - } - - $sqlValue[] = "( $sql like '%" . CRM_Core_DAO::VALUE_SEPARATOR . $k . CRM_Core_DAO::VALUE_SEPARATOR . "%' ) "; - } - } - //if user check only 'CiviCRM_OP_OR' check box - //of custom checkbox field, then ignore this field. - if (!empty($sqlValue)) { - $this->_where[$grouping][] = ' ( ' . implode($sqlOP, $sqlValue) . ' ) '; - $this->_qill[$grouping][] = "{$field['label']} $op $qillValue ( $sqlOPlabel )"; - } - // for multi select - } - else { - foreach ($value as $k => $v) { - if ($v == 'CiviCRM_OP_OR') { - $sqlOP = ' OR '; - $sqlOPlabel = ts('match ANY'); - continue; - } - $v = CRM_Core_DAO::escapeString($v); - $sqlValue[] = "( $sql like '%" . CRM_Core_DAO::VALUE_SEPARATOR . $v . CRM_Core_DAO::VALUE_SEPARATOR . "%' ) "; - } - //if user select only 'CiviCRM_OP_OR' value - //of custom multi select field, then ignore this field. - if (!empty($sqlValue)) { - $this->_where[$grouping][] = ' ( ' . implode($sqlOP, $sqlValue) . ' ) '; - $this->_qill[$grouping][] = "$field[label] $op $qillValue ( $sqlOPlabel )"; - } - } + + if ($field['is_search_range'] && is_array($value)) { + $this->searchRange($field['id'], + $field['label'], + $field['data_type'], + $fieldName, + $value, + $grouping + ); } else { - if ($field['is_search_range'] && is_array($value)) { - $this->searchRange($field['id'], - $field['label'], - $field['data_type'], - $fieldName, - $value, - $grouping - ); + if (in_array($field['html_type'], array('Select', 'Radio', 'Autocomplete-Select'))) { + $wildcard = FALSE; + $val = CRM_Utils_Type::escape($value, 'String'); } else { - if (in_array($field['html_type'], array('Select', 'Radio', 'Autocomplete-Select'))) { - $wildcard = FALSE; - $val = CRM_Utils_Type::escape($value, 'String'); - } - else { - $val = CRM_Utils_Type::escape($strtolower(trim($value)), 'String'); - } - - if ($wildcard) { - $val = $strtolower(CRM_Core_DAO::escapeString($val)); - $val = "%$val%"; - $op = 'LIKE'; - } - - //FIX for custom data query fired against no value(NULL/NOT NULL) - $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($sql, $op, $val, $field['data_type']); - $this->_qill[$grouping][] = "$field[label] $op $qillValue"; + $val = CRM_Utils_Type::escape($strtolower(trim($value)), 'String'); + } + + if ($wildcard) { + $val = $strtolower(CRM_Core_DAO::escapeString($val)); + $val = "%$val%"; + $op = 'LIKE'; } + + //FIX for custom data query fired against no value(NULL/NOT NULL) + $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($sql, $op, $val, $field['data_type']); + $this->_qill[$grouping][] = "$field[label] $op $qillValue"; } - continue; + break; case 'ContactReference': $label = $value ? CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $value, 'sort_name') : ''; $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String'); $this->_qill[$grouping][] = $field['label'] . " $op $label"; - continue; + break; case 'Int': if ($field['is_search_range'] && is_array($value)) { @@ -451,7 +431,7 @@ SELECT label, value $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Integer'); $this->_qill[$grouping][] = $field['label'] . " $op $value"; } - continue; + break; case 'Boolean': if (strtolower($value) == 'yes' || strtolower($value) == strtolower(ts('Yes'))) { @@ -464,12 +444,12 @@ SELECT label, value $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Integer'); $value = $value ? ts('Yes') : ts('No'); $this->_qill[$grouping][] = $field['label'] . " {$op} {$value}"; - continue; + break; case 'Link': $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String'); $this->_qill[$grouping][] = $field['label'] . " $op $value"; - continue; + break; case 'Float': if ($field['is_search_range'] && is_array($value)) { @@ -479,7 +459,7 @@ SELECT label, value $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Float'); $this->_qill[$grouping][] = $field['label'] . " {$op} {$value}"; } - continue; + break; case 'Money': if ($field['is_search_range'] && is_array($value)) { @@ -495,12 +475,12 @@ SELECT label, value $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'Float'); $this->_qill[$grouping][] = $field['label'] . " {$op} {$value}"; } - continue; + break; case 'Memo': $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String'); $this->_qill[$grouping][] = "$field[label] $op $value"; - continue; + break; case 'Date': $fromValue = CRM_Utils_Array::value('from', $value); @@ -544,34 +524,13 @@ SELECT label, value $this->_qill[$grouping][] = $field['label'] . ' <= ' . CRM_Utils_Date::customFormat($toDate); } } - continue; + break; case 'StateProvince': case 'Country': - if (!is_array($value)) { - $this->_where[$grouping][] = "$fieldName {$op} " . CRM_Utils_Type::escape($value, 'Int'); - $this->_qill[$grouping][] = $field['label'] . " {$op} {$qillValue}"; - } - else { - $sqlOP = ' AND '; - $sqlOPlabel = ts('match ALL'); - foreach ($value as $k => $v) { - if ($v == 'CiviCRM_OP_OR') { - $sqlOP = ' OR '; - $sqlOPlabel = ts('match ANY'); - continue; - } - $sqlValue[] = "( $fieldName like '%" . CRM_Core_DAO::VALUE_SEPARATOR . $v . CRM_Core_DAO::VALUE_SEPARATOR . "%' ) "; - } - - //if user select only 'CiviCRM_OP_OR' value - //of custom multi select field, then ignore this field. - if (!empty($sqlValue)) { - $this->_where[$grouping][] = " ( " . implode($sqlOP, $sqlValue) . " ) "; - $this->_qill[$grouping][] = "$field[label] $op $qillValue ( $sqlOPlabel )"; - } - } - continue; + $this->_where[$grouping][] = "$fieldName {$op} " . CRM_Utils_Type::escape($value, 'Int'); + $this->_qill[$grouping][] = $field['label'] . " {$op} {$qillValue}"; + break; case 'File': if ( $op == 'IS NULL' || $op == 'IS NOT NULL' || $op == 'IS EMPTY' || $op == 'IS NOT EMPTY' ) { @@ -586,7 +545,7 @@ SELECT label, value $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op); $this->_qill[$grouping][] = $field['label'] . " {$op} "; } - continue; + break; } } } diff --git a/CRM/Profile/Page/Listings.php b/CRM/Profile/Page/Listings.php index a505ec9b22..1cdfb5fae8 100644 --- a/CRM/Profile/Page/Listings.php +++ b/CRM/Profile/Page/Listings.php @@ -158,12 +158,8 @@ class CRM_Profile_Page_Listings extends CRM_Core_Page { foreach ($this->_fields as $name => $field) { if ((substr($name, 0, 6) == 'custom') && !empty($field['is_search_range'])) { - $from = CRM_Utils_Request::retrieve($name . '_from', 'String', - $this, FALSE, NULL, 'REQUEST' - ); - $to = CRM_Utils_Request::retrieve($name . '_to', 'String', - $this, FALSE, NULL, 'REQUEST' - ); + $from = CRM_Utils_Request::retrieve($name . '_from', 'String', $this); + $to = CRM_Utils_Request::retrieve($name . '_to', 'String', $this); $value = array(); if ($from && $to) { $value['from'] = $from; @@ -248,6 +244,10 @@ class CRM_Profile_Page_Listings extends CRM_Core_Page { if (!is_array($value)) { $value = trim($value); } + $operator = CRM_Utils_Request::retrieve($name . '_operator', 'String', $this); + if ($operator) { + $this->_params[$name . '_operator'] = $operator; + } $this->_params[$name] = $this->_fields[$name]['value'] = $value; } } diff --git a/templates/CRM/Custom/Form/Search.tpl b/templates/CRM/Custom/Form/Search.tpl index 2dd5b37f38..7d524d69bf 100644 --- a/templates/CRM/Custom/Form/Search.tpl +++ b/templates/CRM/Custom/Form/Search.tpl @@ -33,45 +33,9 @@
{foreach from=$cd_edit.fields item=element key=field_id} - {assign var="element_name" value='custom_'|cat:$field_id} - {if $element.options_per_line != 0} - - - - - {else} {assign var="type" value=`$element.html_type`} {assign var="element_name" value='custom_'|cat:$field_id} + {assign var="operator_name" value='custom_'|cat:$field_id|cat:'_operator'} {if $element.is_search_range} {assign var="element_name_from" value=$element_name|cat:"_from"} {assign var="element_name_to" value=$element_name|cat:"_to"} @@ -93,6 +57,9 @@ {elseif $element.skip_calendar NEQ true } {include file="CRM/common/jcalendar.tpl" elementName=$element_name} {/if} + {if !empty($form.$operator_name)} + {$form.$operator_name.html} + {/if} {/if} {if $element.html_type eq 'Autocomplete-Select'} {if $element.data_type eq 'ContactReference'} @@ -101,7 +68,6 @@ {/if} - {/if} {/foreach}
{$form.$element_name.label} - {assign var="count" value="1"} - {strip} - - - {* sort by fails for option per line. Added a variable to iterate through the element array*} - {assign var="index" value="1"} - {foreach name=outer key=key item=item from=$form.$element_name} - {if $index < 10} {* Hack to skip QF field properties that are not checkbox elements. *} - {assign var="index" value=`$index+1`} - {else} - {if $element.html_type EQ 'CheckBox' AND $smarty.foreach.outer.last EQ 1} {* Put 'match ANY / match ALL' checkbox in separate row. *} - - - - {else} - - {if $count EQ $element.options_per_line} - - - {assign var="count" value="1"} - {else} - {assign var="count" value=`$count+1`} - {/if} - {/if} - {/if} - {/foreach} - -
{$form.$element_name.$key.html}{$form.$element_name.$key.html}
- {/strip} -
diff --git a/templates/CRM/Profile/Form/Search.tpl b/templates/CRM/Profile/Form/Search.tpl index 110c10d491..948e697655 100644 --- a/templates/CRM/Profile/Form/Search.tpl +++ b/templates/CRM/Profile/Form/Search.tpl @@ -40,6 +40,7 @@ {continue} {/if} {assign var=n value=$field.name} + {assign var="operator_name" value=$n|cat:'_operator'} {if $field.is_search_range} {assign var=from value=$field.name|cat:'_from'} {assign var=to value=$field.name|cat:'_to'} @@ -55,41 +56,6 @@   {$form.$to.label}  {include file="CRM/common/jcalendar.tpl" elementName=$to} {/if} - {elseif $field.options_per_line} - - {$form.$n.label} - - {assign var="count" value="1"} - {strip} - - - {* sort by fails for option per line. Added a variable to iterate through the element array*} - {assign var="index" value="1"} - {foreach name=outer key=key item=item from=$form.$n} - {if $index < 10} {* Hack to skip QF field properties that are not checkbox elements. *} - {assign var="index" value=`$index+1`} - {else} - {if $field.html_type EQ 'CheckBox' AND $smarty.foreach.outer.last EQ 1} {* Put 'match ANY / match ALL' checkbox in separate row. *} - - - - {else} - - {if $count EQ $field.options_per_line} - - - {assign var="count" value="1"} - {else} - {assign var="count" value=`$count+1`} - {/if} - {/if} - {/if} - {/foreach} - -
{$form.$n.$key.html}{$form.$n.$key.html}
- {/strip} - - {else} @@ -119,10 +85,11 @@ {else} {$form.$n.html} {/if} - {if $field.html_type eq 'Autocomplete-Select'} - {if $field.data_type eq 'ContactReference'} - {include file="CRM/Custom/Form/ContactReference.tpl" element_name = $n} - {/if} + {if $field.html_type eq 'Autocomplete-Select' and $field.data_type eq 'ContactReference'} + {include file="CRM/Custom/Form/ContactReference.tpl" element_name = $n} + {/if} + {if !empty($form.$operator_name)} + {$form.$operator_name.html} {/if} {/if} -- 2.25.1