From 58eaa0925676a52d570282e282ea2710adb92bc9 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Tue, 28 Jul 2015 11:00:46 -0400 Subject: [PATCH] CRM-11856 - Update custom values when option values are modified --- CRM/Core/BAO/CustomOption.php | 43 +++++++++++++ CRM/Core/BAO/OptionValue.php | 4 ++ api/v3/CustomField.php | 16 +++++ tests/phpunit/api/v3/CustomValueTest.php | 79 ++++++++++++++++++++++++ 4 files changed, 142 insertions(+) diff --git a/CRM/Core/BAO/CustomOption.php b/CRM/Core/BAO/CustomOption.php index 48d86991ab..559139a1d1 100644 --- a/CRM/Core/BAO/CustomOption.php +++ b/CRM/Core/BAO/CustomOption.php @@ -416,4 +416,47 @@ SET {$dao->columnName} = REPLACE( {$dao->columnName}, %1, %2 )"; return $options; } + /** + * When changing the value of an option this is called to update all corresponding custom data + * + * @param int $optionId + * @param string $newValue + */ + public static function updateValue($optionId, $newValue) { + $optionValue = new CRM_Core_DAO_OptionValue(); + $optionValue->id = $optionId; + $optionValue->find(TRUE); + $oldValue = $optionValue->value; + if ($oldValue == $newValue) { + return; + } + + $customField = new CRM_Core_DAO_CustomField(); + $customField->option_group_id = $optionValue->option_group_id; + $customField->find(); + while ($customField->fetch()) { + $customGroup = new CRM_Core_DAO_CustomGroup(); + $customGroup->id = $customField->custom_group_id; + $customGroup->find(TRUE); + if (CRM_Core_BAO_CustomField::isSerialized($customField)) { + $params = array( + 1 => array(CRM_Utils_Array::implodePadded($oldValue), 'String'), + 2 => array(CRM_Utils_Array::implodePadded($newValue), 'String'), + 3 => array('%' . CRM_Utils_Array::implodePadded($oldValue) . '%', 'String'), + ); + } + else { + $params = array( + 1 => array($oldValue, 'String'), + 2 => array($newValue, 'String'), + 3 => array($oldValue, 'String'), + ); + } + $sql = "UPDATE `{$customGroup->table_name}` SET `{$customField->column_name}` = REPLACE(`{$customField->column_name}`, %1, %2) WHERE `{$customField->column_name}` LIKE %3"; + $customGroup->free(); + CRM_Core_DAO::executeQuery($sql, $params); + } + $customField->free(); + } + } diff --git a/CRM/Core/BAO/OptionValue.php b/CRM/Core/BAO/OptionValue.php index 64ee49689d..56598ab18b 100644 --- a/CRM/Core/BAO/OptionValue.php +++ b/CRM/Core/BAO/OptionValue.php @@ -182,6 +182,10 @@ class CRM_Core_BAO_OptionValue extends CRM_Core_DAO_OptionValue { $params['is_optgroup'] = CRM_Utils_Array::value('is_optgroup', $params, FALSE); $params['filter'] = CRM_Utils_Array::value('filter', $params, FALSE); } + // Update custom field data to reflect the new value + elseif (isset($params['value'])) { + CRM_Core_BAO_CustomOption::updateValue($ids['optionValue'], $params['value']); + } // action is taken depending upon the mode $optionValue = new CRM_Core_DAO_OptionValue(); diff --git a/api/v3/CustomField.php b/api/v3/CustomField.php index 1d8daa570b..1b46d6f7e2 100644 --- a/api/v3/CustomField.php +++ b/api/v3/CustomField.php @@ -48,7 +48,18 @@ function civicrm_api3_custom_field_create($params) { // Array created for passing options in params. if (isset($params['option_values']) && is_array($params['option_values'])) { + $weight = 0; foreach ($params['option_values'] as $key => $value) { + // Translate simple key/value pairs into full-blown option values + if (!is_array($value)) { + $value = array( + 'label' => $value, + 'value' => $key, + 'is_active' => 1, + 'weight' => $weight, + ); + $key = $weight++; + } $params['option_label'][$key] = $value['label']; $params['option_value'][$key] = $value['value']; $params['option_status'][$key] = $value['is_active']; @@ -80,6 +91,11 @@ function _civicrm_api3_custom_field_create_spec(&$params) { $params['label']['api.required'] = 1; $params['custom_group_id']['api.required'] = 1; $params['is_active']['api.default'] = 1; + $params['option_values'] = array( + 'title' => 'Option Values', + 'description' => "Pass an array of options (value => label) to create this field's option values", + ); + // TODO: Why expose this to the api at all? $params['option_type'] = array( 'title' => 'Option Type', 'description' => 'This (boolean) field tells the BAO to create an option group for the field if the field type is appropriate', diff --git a/tests/phpunit/api/v3/CustomValueTest.php b/tests/phpunit/api/v3/CustomValueTest.php index bd7b73dcff..ba2c2b1719 100644 --- a/tests/phpunit/api/v3/CustomValueTest.php +++ b/tests/phpunit/api/v3/CustomValueTest.php @@ -174,4 +174,83 @@ class api_v3_CustomValueTest extends CiviUnitTestCase { $this->assertEquals('second multi value 3', $result['values'][$firstCustomField]['latest']); } + /** + * Ensure custom data is updated when option values are modified + * + * @link https://issues.civicrm.org/jira/browse/CRM-11856 + * + * @throws \CiviCRM_API3_Exception + */ + public function testAlterOptionValue() { + $selectField = $this->customFieldCreate(array( + 'custom_group_id' => $this->ids['single']['custom_group_id'], + 'label' => 'Custom Select', + 'html_type' => 'Select', + 'option_values' => array( + 'one' => 'Option1', + 'two' => 'Option2', + 'notone' => 'OptionNotOne', + ), + )); + $selectField = civicrm_api3('customField', 'getsingle', array('id' => $selectField['id'])); + $radioField = $this->customFieldCreate(array( + 'custom_group_id' => $this->ids['single']['custom_group_id'], + 'label' => 'Custom Radio', + 'html_type' => 'Radio', + 'option_group_id' => $selectField['option_group_id'], + )); + $multiSelectField = $this->customFieldCreate(array( + 'custom_group_id' => $this->ids['single']['custom_group_id'], + 'label' => 'Custom Multi-Select', + 'html_type' => 'Multi-Select', + 'option_group_id' => $selectField['option_group_id'], + )); + $selectName = 'custom_' . $selectField['id']; + $radioName = 'custom_' . $radioField['id']; + $multiSelectName = 'custom_' . $multiSelectField['id']; + $controlFieldName = 'custom_' . $this->ids['single']['custom_field_id']; + + $params = array( + 'first_name' => 'abc4', + 'last_name' => 'xyz4', + 'contact_type' => 'Individual', + 'email' => 'man4@yahoo.com', + $selectName => 'one', + $multiSelectName => array('one', 'two', 'notone'), + $radioName => 'notone', + // The control group in a science experiment should be unaffected + $controlFieldName => 'one', + ); + + $contact = $this->callAPISuccess('Contact', 'create', $params); + + $result = $this->callAPISuccess('Contact', 'getsingle', array( + 'id' => $contact['id'], + 'return' => array($selectName, $multiSelectName), + )); + $this->assertEquals('one', $result[$selectName]); + $this->assertEquals(array('one', 'two', 'notone'), $result[$multiSelectName]); + + $this->callAPISuccess('OptionValue', 'create', array( + 'value' => 'one-modified', + 'option_group_id' => $selectField['option_group_id'], + 'name' => 'Option1', + 'options' => array( + 'match-mandatory' => array('option_group_id', 'name'), + ), + )); + + $result = $this->callAPISuccess('Contact', 'getsingle', array( + 'id' => $contact['id'], + 'return' => array($selectName, $multiSelectName, $controlFieldName, $radioName), + )); + // Ensure the relevant fields have been updated + $this->assertEquals('one-modified', $result[$selectName]); + $this->assertEquals(array('one-modified', 'two', 'notone'), $result[$multiSelectName]); + // This field should not have changed because we didn't alter this option + $this->assertEquals('notone', $result[$radioName]); + // This should not have changed because this field doesn't use the affected option group + $this->assertEquals('one', $result[$controlFieldName]); + } + } -- 2.25.1