From: Eileen McNaughton Date: Thu, 9 Jun 2022 03:18:48 +0000 (+1200) Subject: dev/core#3498 Fix mishandled option values X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=86b783d8c75410d387d2b702610d07a36fff04eb;p=civicrm-core.git dev/core#3498 Fix mishandled option values --- diff --git a/CRM/Custom/Import/Parser/Api.php b/CRM/Custom/Import/Parser/Api.php index 0ab33abf73..a8a0020840 100644 --- a/CRM/Custom/Import/Parser/Api.php +++ b/CRM/Custom/Import/Parser/Api.php @@ -1,5 +1,6 @@ $customGroupID]; - $group = CustomGroup::get(FALSE)->addSelect('extends')->addWhere('id', '=', $customGroupID)->execute()->first(); - $allFields = civicrm_api3('custom_field', 'get', $params); - $fields = $allFields['values']; - foreach ($fields as $id => $values) { + $fields = (array) CustomField::get(FALSE) + ->addSelect('*', 'custom_group_id.is_multiple', 'custom_group_id.name', 'custom_group_id.extends') + ->addWhere('custom_group_id', '=', $customGroupID)->execute(); + + foreach ($fields as $values) { $datatype = $values['data_type'] ?? NULL; if ($datatype === 'File') { continue; } /* generate the key for the fields array */ - $key = "custom_$id"; - $regexp = preg_replace('/[.,;:!?]/', '', CRM_Utils_Array::value(0, $values)); + $key = 'custom_' . $values['id']; + $regexp = preg_replace('/[.,;:!?]/', '', $values['label']); $importableFields[$key] = [ 'name' => $key, 'title' => $values['label'] ?? NULL, 'headerPattern' => '/' . preg_quote($regexp, '/') . '/', 'import' => 1, - 'custom_field_id' => $id, - 'options_per_line' => $values['options_per_line'] ?? NULL, - 'data_type' => $values['data_type'] ?? NULL, - 'html_type' => $values['html_type'] ?? NULL, + 'custom_field_id' => $values['id'], + 'options_per_line' => $values['options_per_line'], + 'data_type' => $values['data_type'], + 'html_type' => $values['html_type'], 'type' => CRM_Core_BAO_CustomField::dataToType()[$values['data_type']], - 'is_search_range' => $values['is_search_range'] ?? NULL, - 'date_format' => $values['date_format'] ?? NULL, - 'time_format' => $values['time_format'] ?? NULL, - 'extends' => $group['extends'], + 'is_search_range' => $values['is_search_range'], + 'date_format' => $values['date_format'], + 'time_format' => $values['time_format'], + 'extends' => $values['custom_group_id.extends'], + 'custom_group_id' => $customGroupID, + 'custom_group_id.name' => $values['custom_group_id.name'], + 'is_multiple' => $values['custom_group_id.is_multiple'], ]; } return $importableFields; diff --git a/CRM/Import/Parser.php b/CRM/Import/Parser.php index 3f84b93ef7..099e0afd5d 100644 --- a/CRM/Import/Parser.php +++ b/CRM/Import/Parser.php @@ -1441,19 +1441,28 @@ abstract class CRM_Import_Parser { } $optionFieldName = empty($fieldMap[$fieldName]) ? $fieldMetadata['name'] : $fieldName; - if (!empty($fieldMetadata['custom_group_id'])) { - $customField = CustomField::get(FALSE) - ->addWhere('id', '=', $fieldMetadata['custom_field_id']) - ->addSelect('name', 'custom_group_id.name') - ->execute() - ->first(); - $optionFieldName = $customField['custom_group_id.name'] . '.' . $customField['name']; - } - $options = civicrm_api4($this->getFieldEntity($fieldName), 'getFields', [ - 'loadOptions' => ['id', 'name', 'label', 'abbr'], - 'where' => [['name', '=', $optionFieldName]], - 'select' => ['options'], - ])->first()['options']; + if (!empty($fieldMetadata['custom_field_id']) && !empty($fieldMetadata['is_multiple'])) { + $options = civicrm_api4('Custom_' . $fieldMetadata['custom_group_id.name'], 'getFields', [ + 'loadOptions' => ['id', 'name', 'label', 'abbr'], + 'where' => [['custom_field_id', '=', $fieldMetadata['custom_field_id']]], + 'select' => ['options'], + ])->first()['options']; + } + else { + if (!empty($fieldMetadata['custom_group_id'])) { + $customField = CustomField::get(FALSE) + ->addWhere('id', '=', $fieldMetadata['custom_field_id']) + ->addSelect('name', 'custom_group_id.name') + ->execute() + ->first(); + $optionFieldName = $customField['custom_group_id.name'] . '.' . $customField['name']; + } + $options = civicrm_api4($this->getFieldEntity($fieldName), 'getFields', [ + 'loadOptions' => ['id', 'name', 'label', 'abbr'], + 'where' => [['name', '=', $optionFieldName]], + 'select' => ['options'], + ])->first()['options']; + } if (is_array($options)) { // We create an array of the possible variants - notably including // name AND label as either might be used. We also lower case before checking diff --git a/tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php b/tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php index 19c11d37dc..88cb414661 100644 --- a/tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php +++ b/tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php @@ -26,11 +26,6 @@ class CRM_Contribute_Import_Parser_ContributionTest extends CiviUnitTestCase { */ protected $entity = 'Contribution'; - /** - * @var int - */ - protected $userJobID; - /** * Cleanup function. * @@ -363,21 +358,49 @@ class CRM_Contribute_Import_Parser_ContributionTest extends CiviUnitTestCase { } /** - * @param array $mappings + * Get the import's datasource form. * - * @return array + * Defaults to contribution - other classes should override. + * + * @param array $submittedValues + * + * @return \CRM_Contribute_Import_Form_DataSource|\CRM_Core_Form|\CRM_Custom_Import_Form_DataSource + * @noinspection PhpUnnecessaryLocalVariableInspection */ - protected function getMapperFromFieldMappings(array $mappings): array { - $mapper = []; - foreach ($mappings as $mapping) { - $fieldInput = [$mapping['name']]; - if (!empty($mapping['soft_credit_type_id'])) { - $fieldInput[1] = $mapping['soft_credit_match_field']; - $fieldInput[2] = $mapping['soft_credit_type_id']; - } - $mapper[] = $fieldInput; - } - return $mapper; + protected function getDataSourceForm(array $submittedValues) { + return $this->getFormObject('CRM_Contribute_Import_Form_DataSource', $submittedValues); + } + + /** + * Get the import's mapField form. + * + * Defaults to contribution - other classes should override. + * + * @param array $submittedValues + * + * @return \CRM_Contribute_Import_Form_MapField + * @noinspection PhpUnnecessaryLocalVariableInspection + */ + protected function getMapFieldForm(array $submittedValues): CRM_Contribute_Import_Form_MapField { + /* @var \CRM_Contribute_Import_Form_MapField $form */ + $form = $this->getFormObject('CRM_Contribute_Import_Form_MapField', $submittedValues); + return $form; + } + + /** + * Get the import's preview form. + * + * Defaults to contribution - other classes should override. + * + * @param array $submittedValues + * + * @return \CRM_Contribute_Import_Form_Preview + * @noinspection PhpUnnecessaryLocalVariableInspection + */ + protected function getPreviewForm(array $submittedValues): CRM_Contribute_Import_Form_Preview { + /* @var CRM_Contribute_Import_Form_Preview $form */ + $form = $this->getFormObject('CRM_Contribute_Import_Form_Preview', $submittedValues); + return $form; } } diff --git a/tests/phpunit/CRM/Custom/Import/Parser/ApiTest.php b/tests/phpunit/CRM/Custom/Import/Parser/ApiTest.php new file mode 100644 index 0000000000..05d261b119 --- /dev/null +++ b/tests/phpunit/CRM/Custom/Import/Parser/ApiTest.php @@ -0,0 +1,90 @@ +individualCreate(); + $this->createCustomGroupWithFieldOfType(['is_multiple' => TRUE, 'extends' => 'Contact'], 'select', 'level'); + $customGroupID = $this->ids['CustomGroup']['level']; + $dateFieldID = $this->createDateCustomField(['date_format' => 'yy', 'custom_group_id' => $customGroupID])['id']; + $this->importCSV('custom_data_date_select.csv', [ + ['name' => 'contact_id'], + ['name' => $this->getCustomFieldName('levelselect')], + ['name' => 'do_not_import'], + ['name' => 'custom_' . $dateFieldID], + ], ['multipleCustomData' => $customGroupID]); + $dataSource = new CRM_Import_DataSource_CSV($this->userJobID); + $row = $dataSource->getRow(); + $this->assertEquals('IMPORTED', $row['_status']); + $row = $dataSource->getRow(); + $this->assertEquals('IMPORTED', $row['_status']); + $row = $dataSource->getRow(); + $this->assertEquals('ERROR', $row['_status']); + } + + + /** + * Get the import's datasource form. + * + * Defaults to contribution - other classes should override. + * + * @param array $submittedValues + * + * @return \CRM_Custom_Import_Form_DataSource + * @noinspection PhpUnnecessaryLocalVariableInspection + */ + protected function getDataSourceForm(array $submittedValues): CRM_Custom_Import_Form_DataSource { + /* @var \CRM_Custom_Import_Form_DataSource $form */ + $form = $this->getFormObject('CRM_Custom_Import_Form_DataSource', $submittedValues); + return $form; + } + + /** + * Get the import's mapField form. + * + * Defaults to contribution - other classes should override. + * + * @param array $submittedValues + * + * @return \CRM_Custom_Import_Form_MapField + * @noinspection PhpUnnecessaryLocalVariableInspection + */ + protected function getMapFieldForm(array $submittedValues): CRM_Custom_Import_Form_MapField { + /* @var \CRM_Custom_Import_Form_MapField $form */ + $form = $this->getFormObject('CRM_Custom_Import_Form_MapField', $submittedValues); + return $form; + } + + /** + * Get the import's preview form. + * + * Defaults to contribution - other classes should override. + * + * @param array $submittedValues + * + * @return \CRM_Custom_Import_Form_Preview + * @noinspection PhpUnnecessaryLocalVariableInspection + */ + protected function getPreviewForm(array $submittedValues): CRM_Custom_Import_Form_Preview { + /* @var CRM_Custom_Import_Form_Preview $form */ + $form = $this->getFormObject('CRM_Custom_Import_Form_Preview', $submittedValues); + return $form; + } + +} diff --git a/tests/phpunit/CRMTraits/Import/ParserTrait.php b/tests/phpunit/CRMTraits/Import/ParserTrait.php index 4531d74ccb..8ed18f0d93 100644 --- a/tests/phpunit/CRMTraits/Import/ParserTrait.php +++ b/tests/phpunit/CRMTraits/Import/ParserTrait.php @@ -16,6 +16,11 @@ */ trait CRMTraits_Import_ParserTrait { + /** + * @var int + */ + protected $userJobID; + /** * Import the csv file values. * @@ -41,9 +46,13 @@ trait CRMTraits_Import_ParserTrait { 'groups' => [], ], $submittedValues); $form = $this->getDataSourceForm($submittedValues); + $values = $_SESSION['_' . $form->controller->_name . '_container']['values']; $form->buildForm(); $form->postProcess(); $this->userJobID = $form->getUserJobID(); + // This gets reset in DataSource so re-do.... + $_SESSION['_' . $form->controller->_name . '_container']['values'] = $values; + $form = $this->getMapFieldForm($submittedValues); $form->setUserJobID($this->userJobID); $form->buildForm(); @@ -57,51 +66,21 @@ trait CRMTraits_Import_ParserTrait { } /** - * Get the import's datasource form. - * - * Defaults to contribution - other classes should override. - * - * @param array $submittedValues - * - * @return \CRM_Contribute_Import_Form_DataSource - * @noinspection PhpUnnecessaryLocalVariableInspection - */ - protected function getDataSourceForm(array $submittedValues): CRM_Contribute_Import_Form_DataSource { - /* @var \CRM_Contribute_Import_Form_DataSource $form */ - $form = $this->getFormObject('CRM_Contribute_Import_Form_DataSource', $submittedValues); - return $form; - } - - /** - * Get the import's mapField form. - * - * Defaults to contribution - other classes should override. - * - * @param array $submittedValues - * - * @return \CRM_Contribute_Import_Form_MapField - * @noinspection PhpUnnecessaryLocalVariableInspection - */ - protected function getMapFieldForm(array $submittedValues): CRM_Contribute_Import_Form_MapField { - /* @var \CRM_Contribute_Import_Form_MapField $form */ - $form = $this->getFormObject('CRM_Contribute_Import_Form_MapField', $submittedValues); - return $form; - } - - /** - * Get the import's preview form. - * - * Defaults to contribution - other classes should override. - * - * @param array $submittedValues + * @param array $mappings * - * @return \CRM_Contribute_Import_Form_Preview - * @noinspection PhpUnnecessaryLocalVariableInspection + * @return array */ - protected function getPreviewForm(array $submittedValues): CRM_Contribute_Import_Form_Preview { - /* @var CRM_Contribute_Import_Form_Preview $form */ - $form = $this->getFormObject('CRM_Contribute_Import_Form_Preview', $submittedValues); - return $form; + protected function getMapperFromFieldMappings(array $mappings): array { + $mapper = []; + foreach ($mappings as $mapping) { + $fieldInput = [$mapping['name']]; + if (!empty($mapping['soft_credit_type_id'])) { + $fieldInput[1] = $mapping['soft_credit_match_field']; + $fieldInput[2] = $mapping['soft_credit_type_id']; + } + $mapper[] = $fieldInput; + } + return $mapper; } } diff --git a/tests/phpunit/CiviTest/CiviUnitTestCase.php b/tests/phpunit/CiviTest/CiviUnitTestCase.php index dca1ecf07b..07baf4ed80 100644 --- a/tests/phpunit/CiviTest/CiviUnitTestCase.php +++ b/tests/phpunit/CiviTest/CiviUnitTestCase.php @@ -3279,6 +3279,18 @@ class CiviUnitTestCase extends PHPUnit\Framework\TestCase { $_SESSION['_' . $form->controller->_name . '_container']['values']['Preview'] = $formValues; return $form; + case 'CRM_Custom_Import_Form_DataSource': + case 'CRM_Custom_Import_Form_MapField': + case 'CRM_Custom_Import_Form_Preview': + $form->controller = new CRM_Custom_Import_Controller(); + $form->controller->setStateMachine(new CRM_Core_StateMachine($form->controller)); + // The submitted values should be set on one or the other of the forms in the flow. + // For test simplicity we set on all rather than figuring out which ones go where.... + $_SESSION['_' . $form->controller->_name . '_container']['values']['DataSource'] = $formValues; + $_SESSION['_' . $form->controller->_name . '_container']['values']['MapField'] = $formValues; + $_SESSION['_' . $form->controller->_name . '_container']['values']['Preview'] = $formValues; + return $form; + case strpos($class, '_Form_') !== FALSE: $form->controller = new CRM_Core_Controller_Simple($class, $pageName); break;