*
* @param string $apiEntity
*
+ * @param array $entityReferenceFields
+ * Field names of any entity reference fields (which will need reformatting to IN syntax).
+ *
* @return array
*/
- public static function convertFormValues(&$formValues, $wildcard = 0, $useEquals = FALSE, $apiEntity = NULL) {
+ public static function convertFormValues(&$formValues, $wildcard = 0, $useEquals = FALSE, $apiEntity = NULL,
+ $entityReferenceFields = array()) {
$params = array();
if (empty($formValues)) {
return $params;
}
foreach ($formValues as $id => $values) {
+ if (self::isAlreadyProcessedForQueryFormat($values)) {
+ $params[] = $values;
+ continue;
+ }
if ($id == 'privacy') {
if (is_array($formValues['privacy'])) {
$op = !empty($formValues['privacy']['do_not_toggle']) ? '=' : '!=';
continue;
}
}
+ elseif (in_array($id, $entityReferenceFields) && !empty($values) && is_string($values) && (strpos($values, ',') !=
+ FALSE)) {
+ $params[] = array($id, 'IN', explode(',', $values), 0, 0);
+ }
else {
$values = CRM_Contact_BAO_Query::fixWhereValues($id, $values, $wildcard, $useEquals, $apiEntity);
);
}
+ /**
+ * Has this field already been reformatting to Query object syntax.
+ *
+ * The form layer passed formValues to this function in preProcess & postProcess. Reason unknown. This seems
+ * to come with associated double queries & is possibly damaging performance.
+ *
+ * However, here we add a tested function to ensure convertFormValues identifies pre-processed fields & returns
+ * them as they are.
+ *
+ * @param mixed $values
+ * Value in formValues for the field.
+ *
+ * @return bool;
+ */
+ protected static function isAlreadyProcessedForQueryFormat($values) {
+ if (!is_array($values)) {
+ return FALSE;
+ }
+ if (($operator = CRM_Utils_Array::value(1, $values)) == FALSE) {
+ return FALSE;
+ }
+ return in_array($operator, CRM_Core_DAO::acceptedSQLOperators());
+ }
+
/**
* Create and query the db for an contact search.
*
*/
protected $_prefix = "member_";
+ /**
+ * Declare entity reference fields as they will need to be converted to using 'IN'.
+ *
+ * @var array
+ */
+ protected $entityReferenceFields = array('membership_type_id');
+
/**
* Processing needed for buildForm and later.
*/
);
}
- $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues);
+ $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues, 0, FALSE, NULL, $this->entityReferenceFields);
$selector = new CRM_Member_Selector_Search($this->_queryParams,
$this->_action,
NULL,
CRM_Core_BAO_CustomValue::fixCustomFieldValue($this->_formValues);
- $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues);
+ $this->_queryParams = CRM_Contact_BAO_Query::convertFormValues($this->_formValues, 0, FALSE, NULL, $this->entityReferenceFields);
$this->set('formValues', $this->_formValues);
$this->set('queryParams', $this->_queryParams);
--- /dev/null
+<?php
+require_once 'CiviTest/CiviUnitTestCase.php';
+/**
+ * Include dataProvider for tests
+ */
+class CRM_Member_BAO_QueryTest extends CiviUnitTestCase {
+
+ /**
+ * Set up function.
+ *
+ * Ensure CiviCase is enabled.
+ */
+ public function setUp() {
+ parent::setUp();
+ CRM_Core_BAO_ConfigSetting::enableComponent('CiviCase');
+ }
+
+ /**
+ * Check that membership type is handled.
+ *
+ * We want to see the following syntaxes for membership_type_id field handled:
+ * 1) membership_type_id => 1
+ */
+ public function testConvertEntityFieldSingleValue() {
+ $formValues = array('membership_type_id' => 2);
+ $params = CRM_Contact_BAO_Query::convertFormValues($formValues, 0, FALSE, NULL, array('membership_type_id'));
+ $this->assertEquals(array('membership_type_id', '=', 2, 0, 0), $params[0]);
+ $obj = new CRM_Contact_BAO_Query($params);
+ $this->assertEquals(array('civicrm_membership.membership_type_id = 2'), $obj->_where[0]);
+ }
+
+ /**
+ * Check that membership type is handled.
+ *
+ * We want to see the following syntaxes for membership_type_id field handled:
+ * 2) membership_type_id => 5,6
+ *
+ * The last of these is the format used prior to converting membership_type_id to an entity reference field.
+ */
+ public function testConvertEntityFieldMultipleValueEntityRef() {
+ $formValues = array('membership_type_id' => '1,2');
+ $params = CRM_Contact_BAO_Query::convertFormValues($formValues, 0, FALSE, NULL, array('membership_type_id'));
+ $this->assertEquals(array('membership_type_id', 'IN', array(1, 2), 0, 0), $params[0]);
+ $obj = new CRM_Contact_BAO_Query($params);
+ $this->assertEquals(array('civicrm_membership.membership_type_id IN ("1", "2")'), $obj->_where[0]);
+ }
+
+ /**
+ * Check that membership type is handled.
+ *
+ * We want to see the following syntaxes for membership_type_id field handled:
+ * 3) membership_type_id => array(5,6)
+ *
+ * The last of these is the format used prior to converting membership_type_id to an entity reference field. It will
+ * be used by pre-existing smart groups.
+ */
+ public function testConvertEntityFieldMultipleValueLegacy() {
+ $formValues = array('membership_type_id' => array(1, 2));
+ $params = CRM_Contact_BAO_Query::convertFormValues($formValues, 0, FALSE, NULL, array('membership_type_id'));
+ $this->assertEquals(array('membership_type_id', 'IN', array(1, 2), 0, 0), $params[0]);
+ $obj = new CRM_Contact_BAO_Query($params);
+ $this->assertEquals(array('civicrm_membership.membership_type_id IN ("1", "2")'), $obj->_where[0]);
+ }
+
+ /**
+ * Check that running convertFormValues more than one doesn't mangle the array.
+ *
+ * Unfortunately the convertFormValues & indeed much of the query code is run in pre-process AND post-process.
+ *
+ * The convertFormValues function should cope with this until such time as we can rationalise that.
+ */
+ public function testConvertEntityFieldMultipleValueEntityRefDoubleRun() {
+ $formValues = array('membership_type_id' => '1,2');
+ $params = CRM_Contact_BAO_Query::convertFormValues($formValues, 0, FALSE, NULL, array('membership_type_id'));
+ $this->assertEquals(array('membership_type_id', 'IN', array(1, 2), 0, 0), $params[0]);
+ $params = CRM_Contact_BAO_Query::convertFormValues($params, 0, FALSE, NULL, array('membership_type_id'));
+ $this->assertEquals(array('membership_type_id', 'IN', array(1, 2), 0, 0), $params[0]);
+ $obj = new CRM_Contact_BAO_Query($params);
+ $this->assertEquals(array('civicrm_membership.membership_type_id IN ("1", "2")'), $obj->_where[0]);
+ }
+
+}