Upgrade saved import names for contacts
authorEileen McNaughton <emcnaughton@wikimedia.org>
Fri, 22 Apr 2022 20:02:42 +0000 (08:02 +1200)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Tue, 3 May 2022 02:04:36 +0000 (14:04 +1200)
style

CRM/Import/ImportProcessor.php
CRM/Upgrade/Incremental/php/FiveFifty.php
tests/phpunit/CRM/Contact/Import/Form/MapFieldTest.php

index 52357e2899f3fdb69247b92c0c8461c11045525f..12b38d6b5326111dea9b890365eac8c9d96c9ede 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+use Civi\Api4\Mapping;
+use Civi\Api4\MappingField;
+
 /**
  * Class CRM_Import_ImportProcessor.
  *
@@ -447,6 +450,29 @@ class CRM_Import_ImportProcessor {
    * @throws \CiviCRM_API3_Exception
    */
   protected function loadSavedMapping() {
+    $fields = civicrm_api3('MappingField', 'get', [
+      'mapping_id' => $this->getMappingID(),
+      'options' => ['limit' => 0],
+    ])['values'];
+    foreach ($fields as $index => $field) {
+      $fieldSpec = $this->getMetadata()[$fields[$index]['name']];
+      $fields[$index]['label'] = $fieldSpec['title'];
+      if (empty($field['location_type_id']) && !empty($fieldSpec['hasLocationType'])) {
+        $fields[$index]['location_type_id'] = 'Primary';
+      }
+    }
+    $this->mappingFields = $this->rekeyBySortedColumnNumbers($fields);
+  }
+
+  /**
+   * Load the mapping from the database into the pre-5.50 format.
+   *
+   * This is preserved as a copy the upgrade script can use - since the
+   * upgrade allows the other to be 'fixed'.
+   *
+   * @throws \CiviCRM_API3_Exception
+   */
+  protected function legacyLoadSavedMapping() {
     $fields = civicrm_api3('MappingField', 'get', [
       'mapping_id' => $this->getMappingID(),
       'options' => ['limit' => 0],
@@ -589,4 +615,33 @@ class CRM_Import_ImportProcessor {
     return [(string) $this->getFieldName($column), $this->getLocationTypeID($column), $this->getPhoneOrIMTypeID($column)];
   }
 
+  /**
+   * This exists for use in the FiveFifty Upgrade
+   *
+   * @throws \API_Exception|\CiviCRM_API3_Exception
+   */
+  public static function convertSavedFields(): void {
+    $mappings = Mapping::get(FALSE)
+      ->setSelect(['id', 'contact_type'])
+      ->addWhere('mapping_type_id:name', '=', 'Import Contact')
+      ->execute();
+
+    foreach ($mappings as $mapping) {
+      $processor = new CRM_Import_ImportProcessor();
+      $processor->setMappingID($mapping['id']);
+      $processor->setMetadata(CRM_Contact_BAO_Contact::importableFields('All'));
+      $processor->legacyLoadSavedMapping();;
+      foreach ($processor->getMappingFields() as $field) {
+        // The if is mostly precautionary against running this more than once
+        // - which is common in dev if not live...
+        if ($field['name']) {
+          MappingField::update(FALSE)
+            ->setValues(['name' => $field['name']])
+            ->addWhere('id', '=', $field['id'])
+            ->execute();
+        }
+      }
+    }
+  }
+
 }
index e6d115c79c970bd5c4caa9eae54d4a0bd688cfd3..00fbbbdde5cb7684f543c7dee0b231d4bcaa0de3 100644 (file)
@@ -29,6 +29,30 @@ class CRM_Upgrade_Incremental_php_FiveFifty extends CRM_Upgrade_Incremental_Base
    */
   public function upgrade_5_50_alpha1($rev): void {
     $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
+    $this->addTask(ts('Convert import mappings to use names'), 'convertMappingFieldLabelsToNames', $rev);
+
+  }
+
+  /**
+   * Convert saved mapping fields for contact imports to use name rather than
+   * label.
+   *
+   * Currently the 'name' column in civicrm_mapping_field holds names like
+   * 'First Name' or, more tragically 'Contact ID (match to contact)'.
+   *
+   * This updates them to hold the name - eg. 'first_name' in conjunction with
+   * a
+   * change in the contact import.
+   *
+   * (Getting the other entities done is a stretch goal).
+   *
+   * @return bool
+   * @throws \API_Exception
+   * @throws \CiviCRM_API3_Exception
+   */
+  public static function convertMappingFieldLabelsToNames(): bool {
+    CRM_Import_ImportProcessor::convertSavedFields();
+    return TRUE;
   }
 
 }
index c4e236b9ba4fa1ceb98578df93abaaa7b9762626..b112e2a8c939c5f564a19187072be408d5886c1f 100644 (file)
@@ -14,6 +14,7 @@
  * File for the CRM_Contact_Import_Form_MapFieldTest class.
  */
 
+use Civi\Api4\MappingField;
 use Civi\Api4\UserJob;
 
 /**
@@ -27,6 +28,14 @@ class CRM_Contact_Import_Form_MapFieldTest extends CiviUnitTestCase {
   use CRM_Contact_Import_MetadataTrait;
   use CRMTraits_Custom_CustomDataTrait;
 
+  /**
+   * Cleanup mappings in DB.
+   */
+  public function tearDown(): void {
+    $this->quickCleanup(['civicrm_mapping', 'civicrm_mapping_field'], TRUE);
+    parent::tearDown();
+  }
+
   /**
    * Map field form.
    *
@@ -58,7 +67,8 @@ class CRM_Contact_Import_Form_MapFieldTest extends CiviUnitTestCase {
    * @throws \CiviCRM_API3_Exception
    */
   public function testSubmit(array $params, array $mapper, array $expecteds = []): void {
-    $form = $this->getMapFieldFormObject();
+    $form = $this->getMapFieldFormObject(['mapper' => $mapper]);
+    /* @var CRM_Contact_Import_Form_MapField $form */
     $form->set('contactType', CRM_Import_Parser::CONTACT_INDIVIDUAL);
     $form->preProcess();
     $form->submit($params, $mapper);
@@ -204,83 +214,12 @@ class CRM_Contact_Import_Form_MapFieldTest extends CiviUnitTestCase {
    * In conjunction with testing our existing  function this  tests the methods we want to migrate to
    * to  clean it up.
    *
-   * @throws \API_Exception
    * @throws \CRM_Core_Exception
    * @throws \CiviCRM_API3_Exception
    */
   public function testLoadSavedMappingDirect(): void {
-    $this->entity = 'Contact';
-    $this->createCustomGroupWithFieldOfType(['title' => 'My Field']);
+    $mapping = $this->storeComplexMapping();
     $this->setUpMapFieldForm();
-    $mapping = $this->callAPISuccess('Mapping', 'create', ['name' => 'my test', 'label' => 'Special custom']);
-    foreach ([
-      [
-        'name' => 'Addressee',
-        'column_number' => '0',
-      ],
-      [
-        'name' => 'Postal Greeting',
-        'column_number' => '1',
-      ],
-      [
-        'name' => 'Phone',
-        'column_number' => '2',
-        'location_type_id' => '1',
-        'phone_type_id' => '1',
-      ],
-      [
-        'name' => 'Street Address',
-        'column_number' => '3',
-      ],
-      [
-        'name' => 'Enter text here :: My Field',
-        'column_number' => '4',
-      ],
-      [
-        'name' => 'Street Address',
-        'column_number' => '5',
-        'location_type_id' => '1',
-      ],
-      [
-        'name' => 'City',
-        'column_number' => '6',
-        'location_type_id' => '1',
-      ],
-      [
-        'name' => 'State Province',
-        'column_number' => '7',
-        'relationship_type_id' => 4,
-        'relationship_direction' => 'a_b',
-        'location_type_id' => '1',
-      ],
-      [
-        'name' => 'Url',
-        'column_number' => '8',
-        'relationship_type_id' => 4,
-        'relationship_direction' => 'a_b',
-        'website_type_id' => 2,
-      ],
-      [
-        'name' => 'Phone',
-        'column_number' => '9',
-        'relationship_type_id' => 4,
-        'location_type_id' => '1',
-        'relationship_direction' => 'a_b',
-        'phone_type_id' => 2,
-      ],
-      [
-        'name' => 'Phone',
-        'column_number' => '10',
-        'location_type_id' => '1',
-        'phone_type_id' => '3',
-      ],
-    ] as $mappingField) {
-      $this->callAPISuccess('MappingField', 'create', array_merge([
-        'mapping_id' => $mapping['id'],
-        'grouping' => 1,
-        'contact_type' => 'Individual',
-      ], $mappingField));
-    }
     $processor = new CRM_Import_ImportProcessor();
     $processor->setMappingID($mapping['id']);
     $processor->setMetadata($this->getContactImportMetadata());
@@ -438,4 +377,121 @@ document.forms.MapField['mapper[0][3]'].style.display = 'none';\n",
     $this->form->set('contactType', CRM_Import_Parser::CONTACT_INDIVIDUAL);
   }
 
+  /**
+   * Tests the routing used in the 5.50 upgrade script to stop using labels...
+   *
+   * @throws \API_Exception
+   * @throws \CiviCRM_API3_Exception
+   */
+  public function testConvertFields(): void {
+    $mapping = $this->storeComplexMapping(TRUE);
+    CRM_Import_ImportProcessor::convertSavedFields();
+    $updatedMapping = MappingField::get()
+      ->addWhere('mapping_id', '=', $mapping['id'])
+      ->addSelect('id', 'name')->execute();
+
+    $expected = [
+      0 => 'addressee',
+      1 => 'postal_greeting',
+      2 => 'phone',
+      3 => 'street_address',
+      4 => 'custom_1',
+      5 => 'street_address',
+      6 => 'city',
+      7 => 'state_province',
+      8 => 'url',
+      9 => 'phone',
+      10 => 'phone',
+    ];
+    foreach ($updatedMapping as $index => $mappingField) {
+      $this->assertEquals($expected[$index], $mappingField['name']);
+    }
+  }
+
+  /**
+   * Store a mapping with a complex set of fields.
+   *
+   * @param bool $legacyMode
+   *
+   * @return array
+   */
+  private function storeComplexMapping(bool $legacyMode = FALSE): array {
+    $this->createCustomGroupWithFieldOfType(['title' => 'My Field']);
+    $mapping = $this->callAPISuccess('Mapping', 'create', [
+      'name' => 'my test',
+      'label' => 'Special custom',
+      'mapping_type_id' => 'Import Contact',
+    ]);
+    foreach (
+      [
+        [
+          'name' => $legacyMode ? 'Addressee' : 'addressee',
+          'column_number' => '0',
+        ],
+        [
+          'name' => $legacyMode ? 'Postal Greeting' : 'postal_greeting',
+          'column_number' => '1',
+        ],
+        [
+          'name' => $legacyMode ? 'Phone' : 'phone',
+          'column_number' => '2',
+          'location_type_id' => '1',
+          'phone_type_id' => '1',
+        ],
+        [
+          'name' => $legacyMode ? 'Street Address' : 'street_address',
+          'column_number' => '3',
+        ],
+        [
+          'name' => $legacyMode ? 'Enter text here :: My Field' : $this->getCustomFieldName('text'),
+          'column_number' => '4',
+        ],
+        [
+          'name' => $legacyMode ? 'Street Address' : 'street_address',
+          'column_number' => '5',
+          'location_type_id' => '1',
+        ],
+        [
+          'name' => $legacyMode ? 'City' : 'city',
+          'column_number' => '6',
+          'location_type_id' => '1',
+        ],
+        [
+          'name' => $legacyMode ? 'State Province' : 'state_province',
+          'column_number' => '7',
+          'relationship_type_id' => 4,
+          'relationship_direction' => 'a_b',
+          'location_type_id' => '1',
+        ],
+        [
+          'name' => $legacyMode ? 'Url' : 'url',
+          'column_number' => '8',
+          'relationship_type_id' => 4,
+          'relationship_direction' => 'a_b',
+          'website_type_id' => 2,
+        ],
+        [
+          'name' => $legacyMode ? 'Phone' : 'phone',
+          'column_number' => '9',
+          'relationship_type_id' => 4,
+          'location_type_id' => '1',
+          'relationship_direction' => 'a_b',
+          'phone_type_id' => 2,
+        ],
+        [
+          'name' => $legacyMode ? 'Phone' : 'phone',
+          'column_number' => '10',
+          'location_type_id' => '1',
+          'phone_type_id' => '3',
+        ],
+      ] as $mappingField) {
+      $this->callAPISuccess('MappingField', 'create', array_merge([
+        'mapping_id' => $mapping['id'],
+        'grouping' => 1,
+        'contact_type' => 'Individual',
+      ], $mappingField));
+    }
+    return $mapping;
+  }
+
 }