Skip to content

Commit

Permalink
[Ref][Import] Start adding testing to validation, simplify
Browse files Browse the repository at this point in the history
  • Loading branch information
eileenmcnaughton committed May 9, 2022
1 parent 4377e33 commit 5047d2b
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 102 deletions.
130 changes: 28 additions & 102 deletions CRM/Contact/Import/Parser/Contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@ class CRM_Contact_Import_Parser_Contact extends CRM_Import_Parser {
protected $_relationships;

protected $_emailIndex;
protected $_firstNameIndex;
protected $_lastNameIndex;

protected $_householdNameIndex;
protected $_organizationNameIndex;

protected $_phoneIndex;

Expand All @@ -55,7 +50,7 @@ class CRM_Contact_Import_Parser_Contact extends CRM_Import_Parser {
protected $_retCode;

protected $_externalIdentifierIndex;
protected $_allExternalIdentifiers;
protected $_allExternalIdentifiers = [];
protected $_parseStreetAddress;

/**
Expand Down Expand Up @@ -184,10 +179,6 @@ public function init() {

$this->_phoneIndex = -1;
$this->_emailIndex = -1;
$this->_firstNameIndex = -1;
$this->_lastNameIndex = -1;
$this->_householdNameIndex = -1;
$this->_organizationNameIndex = -1;
$this->_externalIdentifierIndex = -1;

$index = 0;
Expand All @@ -198,22 +189,8 @@ public function init() {
if (substr($key, 0, 5) == 'phone') {
$this->_phoneIndex = $index;
}
if ($key == 'first_name') {
$this->_firstNameIndex = $index;
}
if ($key == 'last_name') {
$this->_lastNameIndex = $index;
}
if ($key == 'household_name') {
$this->_householdNameIndex = $index;
}
if ($key == 'organization_name') {
$this->_organizationNameIndex = $index;
}

if ($key == 'external_identifier') {
$this->_externalIdentifierIndex = $index;
$this->_allExternalIdentifiers = [];
}
$index++;
}
Expand Down Expand Up @@ -2294,68 +2271,14 @@ public function deprecated_contact_check_params(
$dupeCheck = TRUE,
$dedupeRuleGroupID = NULL) {

$requiredCheck = TRUE;

if (isset($params['id']) && is_numeric($params['id'])) {
$requiredCheck = FALSE;
}
if ($requiredCheck) {
$required = [
'Individual' => [
['first_name', 'last_name'],
'email',
],
'Household' => [
'household_name',
],
'Organization' => [
'organization_name',
],
];

// contact_type has a limited number of valid values
if (empty($params['contact_type'])) {
throw new CRM_Core_Exception("No Contact Type");
}
$fields = $required[$params['contact_type']] ?? NULL;
if ($fields == NULL) {
throw new CRM_Core_Exception("Invalid Contact Type: {$params['contact_type']}");
}

// @todo - ensure this is tested & remove - expectation is api call further
// down validates it.
if ($csType = CRM_Utils_Array::value('contact_sub_type', $params)) {
if (!(CRM_Contact_BAO_ContactType::isExtendsContactType($csType, $params['contact_type']))) {
throw new CRM_Core_Exception("Invalid or Mismatched Contact Subtype: " . implode(', ', (array) $csType));
}
}

if (empty($params['contact_id']) && !empty($params['id'])) {
$valid = FALSE;
$error = '';
foreach ($fields as $field) {
if (is_array($field)) {
$valid = TRUE;
foreach ($field as $element) {
if (empty($params[$element])) {
$valid = FALSE;
$error .= $element;
break;
}
}
}
else {
if (!empty($params[$field])) {
$valid = TRUE;
}
}
if ($valid) {
break;
}
}

if (!$valid) {
throw new CRM_Core_Exception("Required fields not found for {$params['contact_type']} : $error");
}
}
}

if ($dupeCheck) {
Expand Down Expand Up @@ -2595,13 +2518,19 @@ public function setActiveFields($fieldKeys) {
/**
* Format the field values for input to the api.
*
* @param array $values
* The row from the datasource.
*
* @return array
* (reference ) associative array of name/value pairs
* Parameters mapped as described in getMappedRow
*
* @throws \API_Exception
* @todo - clean this up a bit & merge back into `getMappedRow`
*
*/
public function &getActiveFieldParams() {
private function getParams(array $values): array {
$params = [];
$mapper = $this->getSubmittedValue('mapper');

foreach ($this->getFieldMappings() as $i => $mappedField) {
// The key is in the format 5_a_b where 5 is the relationship_type_id and a_b is the direction.
$relatedContactKey = $mappedField['relationship_type_id'] ? ($mappedField['relationship_type_id'] . '_' . $mappedField['relationship_direction']) : NULL;
Expand All @@ -2622,7 +2551,7 @@ public function &getActiveFieldParams() {
$imProviderID = $relatedContactKey ? NULL : $mappedField['im_provider_id'];
$websiteTypeID = $relatedContactKey ? NULL : $mappedField['website_type_id'];

$importedValue = $this->_activeFields[$i]->_value;
$importedValue = $values[$i];

if (isset($importedValue)) {
if (!$relatedContactKey) {
Expand Down Expand Up @@ -3339,8 +3268,7 @@ protected function getRelationshipLabel(int $id, string $direction): string {
* @throws \API_Exception
*/
public function getMappedRow(array $values): array {
$this->setActiveFieldValues($values);
$params = $this->getActiveFieldParams();
$params = $this->getParams($values);
$params['contact_type'] = $this->getContactType();
return $params;
}
Expand All @@ -3364,42 +3292,40 @@ public function isComplete() {
* The values array represents a row in the datasource.
*
* @param array $values
*
* @throws \API_Exception
*/
public function validateValues(array $values): void {
$errorMessage = NULL;
$errorRequired = FALSE;
$params = $this->getMappedRow($values);
switch ($this->_contactType) {
$missingNames = [];
switch ($params['contact_type']) {
case 'Individual':
$missingNames = [];
if ($this->_firstNameIndex < 0 || empty($values[$this->_firstNameIndex])) {
$errorRequired = TRUE;
if (empty($params['first_name'])) {
$missingNames[] = ts('First Name');
}
if ($this->_lastNameIndex < 0 || empty($values[$this->_lastNameIndex])) {
$errorRequired = TRUE;
if (empty($params['last_name'])) {
$missingNames[] = ts('Last Name');
}
if ($errorRequired) {
$and = ' ' . ts('and') . ' ';
$errorMessage = ts('Missing required fields:') . ' ' . implode($and, $missingNames);
}
break;

case 'Household':
if ($this->_householdNameIndex < 0 || empty($values[$this->_householdNameIndex])) {
$errorRequired = TRUE;
$errorMessage = ts('Missing required fields:') . ' ' . ts('Household Name');
if (empty($params['household_name'])) {
$missingNames[] = ts('Missing required fields:') . ' ' . ts('Household Name');
}
break;

case 'Organization':
if ($this->_organizationNameIndex < 0 || empty($values[$this->_organizationNameIndex])) {
$errorRequired = TRUE;
$errorMessage = ts('Missing required fields:') . ' ' . ts('Organization Name');
if (empty($params['organization_name'])) {
$missingNames[] = ts('Missing required fields:') . ' ' . ts('Organization Name');
}
break;
}
if (!empty($missingNames)) {
$errorMessage = ts('Missing required fields:') . ' ' . implode(' ' . ts('and') . ' ', $missingNames);
$errorRequired = TRUE;
}

if ($this->_emailIndex >= 0) {
/* If we don't have the required fields, bail */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
First Name
Joseph
55 changes: 55 additions & 0 deletions tests/phpunit/CRM/Contact/Import/Parser/ContactTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,36 @@ public function testCustomFieldValidation(): void {
$this->assertEquals([], $errorMessage);
}

/**
* Test the import validation.
*
* @dataProvider validateDataProvider
*
* @throws \API_Exception
*/
public function testValidation($csv, $mapper, $expectedError): void {
try {
$this->validateCSV($csv, $mapper);
}
catch (CRM_Core_Exception $e) {
$this->assertSame($expectedError, $e->getMessage());
return;
}
if ($expectedError) {
$this->fail('expected error :' . $expectedError);
}
}

public function validateDataProvider(): array {
return [
'individual_required' => [
'csv' => 'individual_invalid_missing_name.csv',
'mapper' => [['last_name']],
'expected_error' => 'Missing required fields: First Name OR Email Address',
],
];
}

/**
* Test that setting duplicate action to fill doesn't blow away data
* that exists, but does fill in where it's empty.
Expand Down Expand Up @@ -1084,4 +1114,29 @@ protected function getUserJobID($submittedValues = []) {
])->execute()->first()['id'];
}

/**
* Validate the csv file values.
*
* @param string $csv Name of csv file.
* @param array $mapper Mapping as entered on MapField form.
* e.g [['first_name']['email', 1]].
*
* @throws \API_Exception
* @throws \CRM_Core_Exception
*/
protected function validateCSV(string $csv, array $mapper): void {
$userJobID = $this->getUserJobID([
'uploadFile' => ['name' => __DIR__ . '/../Form/data/' . $csv],
'skipColumnHeader' => TRUE,
'fieldSeparator' => ',',
'mapper' => $mapper,
]);
$dataSource = new CRM_Import_DataSource_CSV($userJobID);
$dataSource->initialize();
$parser = new CRM_Contact_Import_Parser_Contact();
$parser->setUserJobID($userJobID);
$parser->init();
$parser->validateValues(array_values($dataSource->getRow()));
}

}

0 comments on commit 5047d2b

Please sign in to comment.