[REF] [Import] Clean up on map fields & preview templates in Contact import
authorEileen McNaughton <emcnaughton@wikimedia.org>
Wed, 20 Apr 2022 06:18:38 +0000 (18:18 +1200)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Thu, 21 Apr 2022 14:56:09 +0000 (02:56 +1200)
This provides a bit of sanity to the MapTable.tpl which is included from
MapField and Preview - the focus being around getting
rid of all the section tags which rely on Count being assigned
and getting back to for-eaching the relevant arrays

CRM/Contact/Import/Form/DataSource.php
CRM/Contact/Import/Form/MapField.php
CRM/Contact/Import/Form/Preview.php
CRM/Contact/Import/Parser/Contact.php
CRM/Import/DataSource.php
CRM/Import/DataSource/CSV.php
CRM/Import/DataSource/SQL.php
CRM/Import/Forms.php
templates/CRM/Contact/Import/Form/MapField.tpl
templates/CRM/Contact/Import/Form/MapTable.tpl
tests/phpunit/CRM/Contact/Import/Form/MapFieldTest.php

index d4626437d4b24fdffe6fb72f2483594c90b8151a..d956721ad7eea1ea1e703759b0182a602103b394 100644 (file)
@@ -246,7 +246,6 @@ class CRM_Contact_Import_Form_DataSource extends CRM_Import_Forms {
     $dao = new CRM_Core_DAO();
     $db = $dao->getDatabaseConnection();
     $dataSource->postProcess($this->_params, $db, $this);
-    $this->updateUserJobMetadata('DataSource', $dataSource->getDataSourceMetadata());
   }
 
   /**
index 5471108423bd6e07c8a83a6c943d9673fc2de75a..acd0ce187ff9eec87a129763dcce97da5fb86c11 100644 (file)
@@ -75,10 +75,12 @@ class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
 
   /**
    * Set variables up before form is built.
+   *
+   * @throws \API_Exception
+   * @throws \CRM_Core_Exception
+   * @throws \Civi\API\Exception\UnauthorizedException
    */
   public function preProcess() {
-    $dataSource = $this->get('dataSource');
-    $skipColumnHeader = $this->get('skipColumnHeader');
     $this->_mapperFields = $this->get('fields');
     $this->_importTableName = $this->get('importTableName');
     $this->_onDuplicate = $this->get('onDuplicate');
@@ -142,35 +144,16 @@ class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
     $this->assign('highlightedFields', $highlightedFields);
     $this->_formattedFieldNames[$contactType] = $this->_mapperFields = array_merge($this->_mapperFields, $formattedFieldNames);
 
-    $columnNames = [];
-    //get original col headers from csv if present.
-    if ($dataSource == 'CRM_Import_DataSource_CSV' && $skipColumnHeader) {
-      $columnNames = $this->get('originalColHeader');
-    }
-    else {
-      // get the field names from the temp. DB table
-      $columnsQuery = "SHOW FIELDS FROM $this->_importTableName
-                         WHERE Field NOT LIKE '\_%'";
-      $columnsResult = CRM_Core_DAO::executeQuery($columnsQuery);
-      while ($columnsResult->fetch()) {
-        $columnNames[] = $columnsResult->Field;
-      }
-    }
-
-    $showColNames = TRUE;
-    if ($dataSource === 'CRM_Import_DataSource_CSV' && !$skipColumnHeader) {
-      $showColNames = FALSE;
-    }
-    $this->assign('showColNames', $showColNames);
+    $columnNames = $this->getColumnHeaders();
+    $this->assign('showColNames', !empty($columnNames));
 
-    $this->_columnCount = count($columnNames);
+    $this->_columnCount = $this->getNumberOfColumns();
     $this->_columnNames = $columnNames;
-    $this->assign('columnNames', $columnNames);
+    $this->assign('columnNames', $this->getColumnHeaders());
     //$this->_columnCount = $this->get( 'columnCount' );
     $this->assign('columnCount', $this->_columnCount);
-    $this->_dataValues = $this->get('dataValues');
+    $this->_dataValues = array_values($this->getDataRows(2));
     $this->assign('dataValues', $this->_dataValues);
-    $this->assign('rowDisplayCount', 2);
   }
 
   /**
@@ -243,7 +226,7 @@ class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
     foreach ($mapperKeys as $key) {
       // check if there is a _a_b or _b_a in the key
       if (strpos($key, '_a_b') || strpos($key, '_b_a')) {
-        list($id, $first, $second) = explode('_', $key);
+        [$id, $first, $second] = explode('_', $key);
       }
       else {
         $id = $first = $second = NULL;
@@ -559,7 +542,7 @@ class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
       }
 
       //relationship contact mapper info.
-      list($id, $first, $second) = CRM_Utils_System::explode('_', $fldName, 3);
+      [$id, $first, $second] = CRM_Utils_System::explode('_', $fldName, 3);
       if (($first === 'a' && $second === 'b') ||
         ($first === 'b' && $second === 'a')
       ) {
@@ -700,7 +683,7 @@ class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
       }
 
       $mappingID = NULL;
-      for ($i = 0; $i < $this->_columnCount; $i++) {
+      foreach (array_keys($this->getColumnHeaders()) as $i) {
         $mappingID = $this->saveMappingField($mapperKeys, $saveMapping, $cType, $i, $mapper, $parserParameters);
       }
       $this->set('savedMapping', $mappingID);
@@ -712,15 +695,14 @@ class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
       $parserParameters['relatedContactPhoneType'], $parserParameters['relatedContactImProvider'],
       $parserParameters['mapperWebsiteType'], $parserParameters['relatedContactWebsiteType']
     );
+    $parser->setUserJobID($this->getUserJobID());
 
-    $primaryKeyName = $this->get('primaryKeyName');
-    $statusFieldName = $this->get('statusFieldName');
     $parser->run($this->_importTableName,
       $mapper,
       CRM_Import_Parser::MODE_PREVIEW,
       $this->get('contactType'),
-      $primaryKeyName,
-      $statusFieldName,
+      '_id',
+      '_status',
       $this->_onDuplicate,
       NULL, NULL, FALSE,
       CRM_Contact_Import_Parser_Contact::DEFAULT_TIMEOUT,
index 9a15ceb6063bde39af386a2e386d7fde97adb068..02816642abb76646a73329ab15dddc1ebe8bf93f 100644 (file)
@@ -31,8 +31,6 @@ class CRM_Contact_Import_Form_Preview extends CRM_Import_Form_Preview {
    * Set variables up before form is built.
    */
   public function preProcess() {
-    //get the data from the session
-    $dataValues = $this->get('dataValues');
     $mapper = $this->get('mapper');
     $invalidRowCount = $this->get('invalidRowCount');
     $conflictRowCount = $this->get('conflictRowCount');
@@ -82,7 +80,6 @@ class CRM_Contact_Import_Form_Preview extends CRM_Import_Form_Preview {
       'locations',
       'phones',
       'ims',
-      'dataValues',
       'columnCount',
       'totalRowCount',
       'validRowCount',
@@ -103,6 +100,7 @@ class CRM_Contact_Import_Form_Preview extends CRM_Import_Form_Preview {
     foreach ($properties as $property) {
       $this->assign($property, $this->get($property));
     }
+    $this->assign('dataValues', $this->getDataRows(2));
 
     $this->setStatusUrl();
 
index b9a80bf4d31b2c95550811cb76320ccfe130be9c..384d0923d7cfbe0e13a8891b8c26857bd24fe3f2 100644 (file)
@@ -184,17 +184,16 @@ class CRM_Contact_Import_Parser_Contact extends CRM_Import_Parser {
     $this->_mapperRelatedContactWebsiteType = $mapperRelatedContactWebsiteType;
     // get IM service provider type id for related contact
     $this->_mapperRelatedContactImProvider = &$mapperRelatedContactImProvider;
+    $this->setFieldMetadata();
+    foreach ($this->getImportableFieldsMetadata() as $name => $field) {
+      $this->addField($name, $field['title'], CRM_Utils_Array::value('type', $field), CRM_Utils_Array::value('headerPattern', $field), CRM_Utils_Array::value('dataPattern', $field), CRM_Utils_Array::value('hasLocationType', $field));
+    }
   }
 
   /**
    * The initializer code, called before processing.
    */
   public function init() {
-    $this->setFieldMetadata();
-    foreach ($this->getImportableFieldsMetadata() as $name => $field) {
-      $this->addField($name, $field['title'], CRM_Utils_Array::value('type', $field), CRM_Utils_Array::value('headerPattern', $field), CRM_Utils_Array::value('dataPattern', $field), CRM_Utils_Array::value('hasLocationType', $field));
-    }
-
     $this->_newContacts = [];
 
     $this->setActiveFields($this->_mapperKeys);
@@ -2598,9 +2597,17 @@ class CRM_Contact_Import_Parser_Contact extends CRM_Import_Parser {
     $this->_conflicts = [];
     $this->_unparsedAddresses = [];
 
+    // Transitional support for deprecating table_name (and other fields)
+    // form input - the goal is to load them from userJob - but eventually
+    // we will just load the datasource object and this code will not know the
+    // table name.
+    if (!$tableName && $this->userJobID) {
+      $tableName = $this->getUserJob()['metadata']['DataSource']['table_name'];
+    }
+
     $this->_tableName = $tableName;
-    $this->_primaryKeyName = $primaryKeyName;
-    $this->_statusFieldName = $statusFieldName;
+    $this->_primaryKeyName = '_id';
+    $this->_statusFieldName = '_status';
 
     if ($mode == self::MODE_MAPFIELD) {
       $this->_rows = [];
index c5a4a44cef99744a9dbb47a4371c75c750e8694d..1fce11a312fe60e12ef8dfba41e6bdba630b4126 100644 (file)
@@ -95,6 +95,83 @@ abstract class CRM_Import_DataSource {
     return $this->userJob;
   }
 
+  /**
+   * Get submitted value.
+   *
+   * Get a value submitted on the form.
+   *
+   * @return mixed
+   *
+   * @throws \API_Exception
+   */
+  protected function getSubmittedValue(string $valueName) {
+    return $this->getUserJob()['metadata']['submitted_values'][$valueName];
+  }
+
+  /**
+   * Get rows as an array.
+   *
+   * The array has all values.
+   *
+   * @param int $limit
+   * @param int $offset
+   *
+   * @return array
+   *
+   * @throws \API_Exception
+   * @throws \CRM_Core_Exception
+   */
+  public function getRows(int $limit = 0, int $offset = 0) {
+    $query = 'SELECT * FROM ' . $this->getTableName();
+    if ($limit) {
+      $query .= ' LIMIT ' . $limit . ($offset ? (' OFFSET ' . $offset) : NULL);
+    }
+    $rows = [];
+    $result = CRM_Core_DAO::executeQuery($query);
+    while ($result->fetch()) {
+      $values = $result->toArray();
+      /* trim whitespace around the values */
+      foreach ($values as $k => $v) {
+        $values[$k] = trim($v, " \t\r\n");
+      }
+      // Historically we expect a non-associative array...
+      $rows[] = array_values($values);
+    }
+    return $rows;
+  }
+
+  /**
+   * Get an array of column headers, if any.
+   *
+   * Null is returned when there are none - ie because a csv file does not
+   * have an initial header row.
+   *
+   * This is presented to the user in the MapField screen so
+   * that can see what fields they are mapping.
+   *
+   * @return array
+   * @throws \API_Exception
+   */
+  public function getColumnHeaders(): array {
+    return $this->getUserJob()['metadata']['DataSource']['column_headers'];
+  }
+
+  /**
+   * Get an array of column headers, if any.
+   *
+   * Null is returned when there are none - ie because a csv file does not
+   * have an initial header row.
+   *
+   * This is presented to the user in the MapField screen so
+   * that can see what fields they are mapping.
+   *
+   * @return int
+   * @throws \API_Exception
+   */
+  public function getNumberOfColumns(): int {
+    return $this->getUserJob()['metadata']['DataSource']['number_of_columns'];
+  }
+
   /**
    * Generated metadata relating to the the datasource.
    *
@@ -112,12 +189,43 @@ abstract class CRM_Import_DataSource {
   protected $dataSourceMetadata = [];
 
   /**
+   * Get metadata about the datasource.
+   *
    * @return array
+   *
+   * @throws \API_Exception
    */
   public function getDataSourceMetadata(): array {
+    if (!$this->dataSourceMetadata && $this->getUserJobID()) {
+      $this->dataSourceMetadata = $this->getUserJob()['metadata']['DataSource'];
+    }
+
     return $this->dataSourceMetadata;
   }
 
+  /**
+   * Get the table name for the datajob.
+   *
+   * @return string|null
+   *
+   * @throws \API_Exception
+   * @throws \CRM_Core_Exception
+   */
+  protected function getTableName(): ?string {
+    // The old name is still stored...
+    $tableName = $this->getDataSourceMetadata()['table_name'];
+    if (!$tableName) {
+      return NULL;
+    }
+    if (strpos($tableName, 'civicrm_tmp_') !== 0
+      || !CRM_Utils_Rule::alphanumeric($tableName)) {
+      // The table name is generated and stored by code, not users so it
+      // should be safe - but a check seems prudent all the same.
+      throw new CRM_Core_Exception('Table cannot be deleted');
+    }
+    return $tableName;
+  }
+
   /**
    * Get the fields declared for this datasource.
    *
@@ -173,4 +281,23 @@ abstract class CRM_Import_DataSource {
     return empty($info['permissions']) || CRM_Core_Permission::check($info['permissions']);
   }
 
+  /**
+   * @param string $key
+   * @param array $data
+   *
+   * @throws \API_Exception
+   * @throws \Civi\API\Exception\UnauthorizedException
+   */
+  protected function updateUserJobMetadata(string $key, array $data): void {
+    $metaData = array_merge(
+      $this->getUserJob()['metadata'],
+      [$key => $data]
+    );
+    UserJob::update(FALSE)
+      ->addWhere('id', '=', $this->getUserJobID())
+      ->setValues(['metadata' => $metaData])
+      ->execute();
+    $this->userJob['metadata'] = $metaData;
+  }
+
 }
index c91ca15a8841776a9399aa220e894e8ca9967bff..a21a4f01f6911e6c7740018147ee71644286dc5f 100644 (file)
@@ -84,23 +84,26 @@ class CRM_Import_DataSource_CSV extends CRM_Import_DataSource {
    * @param string $db
    * @param \CRM_Core_Form $form
    *
+   * @throws \API_Exception
    * @throws \CRM_Core_Exception
    */
   public function postProcess(&$params, &$db, &$form) {
     $file = $params['uploadFile']['name'];
+    $firstRowIsColumnHeader = $params['skipColumnHeader'] ?? FALSE;
     $result = self::_CsvToTable(
       $file,
-      CRM_Utils_Array::value('skipColumnHeader', $params, FALSE),
+      $firstRowIsColumnHeader,
       CRM_Utils_Array::value('import_table_name', $params),
       CRM_Utils_Array::value('fieldSeparator', $params, ',')
     );
 
     $form->set('originalColHeader', CRM_Utils_Array::value('column_headers', $result));
     $form->set('importTableName', $result['import_table_name']);
-    $this->dataSourceMetadata = [
+    $this->updateUserJobMetadata('DataSource', [
       'table_name' => $result['import_table_name'],
-      'column_headers' => $result['column_headers'] ?? NULL,
-    ];
+      'column_headers' => $firstRowIsColumnHeader ? $result['column_headers'] : [],
+      'number_of_columns' => $result['number_of_columns'],
+    ]);
   }
 
   /**
@@ -253,6 +256,7 @@ class CRM_Import_DataSource_CSV extends CRM_Import_DataSource {
 
     //get the import tmp table name.
     $result['import_table_name'] = $tableName;
+    $result['number_of_columns'] = $numColumns;
     return $result;
   }
 
index 2e712f43171e9bfba28256dde44877d03f9e97ba..3d123ce6a900322581c4d92ca6fcf5c4324f29e0 100644 (file)
@@ -71,14 +71,14 @@ class CRM_Import_DataSource_SQL extends CRM_Import_DataSource {
     $errors = [];
 
     // Makeshift query validation (case-insensitive regex matching on word boundaries)
-    $forbidden = ['ALTER', 'CREATE', 'DELETE', 'DESCRIBE', 'DROP', 'SHOW', 'UPDATE', 'information_schema'];
+    $forbidden = ['ALTER', 'CREATE', 'DELETE', 'DESCRIBE', 'DROP', 'SHOW', 'UPDATE', 'REPLACE', 'information_schema'];
     foreach ($forbidden as $pattern) {
       if (preg_match("/\\b$pattern\\b/i", $fields['sqlQuery'])) {
         $errors['sqlQuery'] = ts('The query contains the forbidden %1 command.', [1 => $pattern]);
       }
     }
 
-    return $errors ? $errors : TRUE;
+    return $errors ?: TRUE;
   }
 
   /**
@@ -88,7 +88,9 @@ class CRM_Import_DataSource_SQL extends CRM_Import_DataSource {
    * @param string $db
    * @param \CRM_Core_Form $form
    *
+   * @throws \API_Exception
    * @throws \CRM_Core_Exception
+   * @throws \Civi\API\Exception\UnauthorizedException
    */
   public function postProcess(&$params, &$db, &$form) {
     $importJob = new CRM_Contact_Import_ImportJob(
@@ -97,9 +99,21 @@ class CRM_Import_DataSource_SQL extends CRM_Import_DataSource {
     );
 
     $form->set('importTableName', $importJob->getTableName());
-    $this->dataSourceMetadata = [
+    // Get the names of the fields to be imported. Any fields starting with an
+    // underscore are considered to be internal to the import process)
+    $columnsResult = CRM_Core_DAO::executeQuery(
+      'SHOW FIELDS FROM ' . $importJob->getTableName() . "
+      WHERE Field NOT LIKE '\_%'");
+
+    $columnNames = [];
+    while ($columnsResult->fetch()) {
+      $columnNames[] = $columnsResult->Field;
+    }
+    $this->updateUserJobMetadata('DataSource', [
       'table_name' => $importJob->getTableName(),
-    ];
+      'column_headers' => $columnNames,
+      'number_of_columns' => count($columnNames),
+    ]);
   }
 
 }
index be62a5200e2c343998bfe5d9205da7ec94f19012..b1fc3a4d66c2d6ce5942e12f962b7e3a4bb099cc 100644 (file)
@@ -333,4 +333,52 @@ class CRM_Import_Forms extends CRM_Core_Form {
     $this->userJob['metadata'] = $metaData;
   }
 
+  /**
+   * Get column headers for the datasource or empty array if none apply.
+   *
+   * This would be the first row of a csv or the fields in an sql query.
+   *
+   * If the csv does not have a header row it will be empty.
+   *
+   * @return array
+   *
+   * @throws \API_Exception
+   * @throws \CRM_Core_Exception
+   */
+  protected function getColumnHeaders(): array {
+    return $this->getDataSourceObject()->getColumnHeaders();
+  }
+
+  /**
+   * Get the number of importable columns in the data source.
+   *
+   * @return int
+   *
+   * @throws \API_Exception
+   * @throws \CRM_Core_Exception
+   */
+  protected function getNumberOfColumns(): int {
+    return $this->getDataSourceObject()->getNumberOfColumns();
+  }
+
+  /**
+   * Get x data rows from the datasource.
+   *
+   * At this stage we are fetching from what has been stored in the form
+   * during `postProcess` on the DataSource form.
+   *
+   * In the future we will use the dataSource object, likely
+   * supporting offset as well.
+   *
+   * @param int $limit
+   *
+   * @return array
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \API_Exception
+   */
+  protected function getDataRows(int $limit): array {
+    return $this->getDataSourceObject()->getRows($limit);
+  }
+
 }
index 388b2f77e2bad57533ad200f6397055ac7d1250a..a5f888946da6171c7f7c5023b48720d8a230bb25 100644 (file)
@@ -19,7 +19,7 @@
 </div>
 <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
   {* Table for mapping data to CRM fields *}
- {include file="CRM/Contact/Import/Form/MapTable.tpl}
+ {include file="CRM/Contact/Import/Form/MapTable.tpl" mapper=$form.mapper}
 
 <script type="text/javascript" >
 {literal}
index 5d6f22a44bd5ea9e90d11e8b00b93a50dad5bbf4..79e478c6db8ae386adf7e81768054bd0ce492da4 100644 (file)
     {if $savedMappingName}
         <tr class="columnheader-dark"><th colspan="4">{ts 1=$savedMappingName}Saved Field Mapping: %1{/ts}</td></tr>
     {/if}
-        <tr class="columnheader">
-      {if $showColNames}
-          {assign var="totalRowsDisplay" value=$rowDisplayCount+1}
-      {else}
-          {assign var="totalRowsDisplay" value=$rowDisplayCount}
-      {/if}
-            {section name=rows loop=$totalRowsDisplay}
-                {if $smarty.section.rows.iteration == 1 and $showColNames}
-                  <td>{ts}Column Names{/ts}</td>
-                {elseif $showColNames}
-                  <td>{ts 1=$smarty.section.rows.iteration-1}Import Data (row %1){/ts}</td>
-    {else}
-      <td>{ts 1=$smarty.section.rows.iteration}Import Data (row %1){/ts}</td>
-                {/if}
-            {/section}
 
-            <td>{ts}Matching CiviCRM Field{/ts}</td>
-        </tr>
+    {* Header row - has column for column names if they have been supplied *}
+    <tr class="columnheader">
+      {if $columnNames}
+        <td>{ts}Column Names{/ts}</td>
+      {/if}
+      {foreach from=$dataValues item=row key=index}
+        {math equation="x + y" x=$index y=1 assign="rowNumber"}
+        <td>{ts 1=$rowNumber}Import Data (row %1){/ts}</td>
+      {/foreach}
+      <td>{ts}Matching CiviCRM Field{/ts}</td>
+    </tr>
 
         {*Loop on columns parsed from the import data rows*}
-        {section name=cols loop=$columnCount}
-            {assign var="i" value=$smarty.section.cols.index}
+        {foreach from=$mapper key=i item=mapperField}
+
             <tr style="border: 1px solid #DDDDDD;">
 
-                {if $showColNames}
-                    <td class="even-row labels">{$columnNames[$i]}</td>
+                {if array_key_exists($i, $columnNames)}
+                  <td class="even-row labels">{$columnNames[$i]}</td>
                 {/if}
-
-                {section name=rows loop=$rowDisplayCount}
-                    {assign var="j" value=$smarty.section.rows.index}
-                    <td class="odd-row">{$dataValues[$j][$i]|escape}</td>
-                {/section}
+                {foreach from=$dataValues item=row key=index}
+                  <td class="odd-row">{$row[$i]|escape}</td>
+                {/foreach}
 
                 {* Display mapper <select> field for 'Map Fields', and mapper value for 'Preview' *}
                 <td class="form-item even-row{if $wizard.currentStepName == 'Preview'} labels{/if}">
-                    {if $wizard.currentStepName == 'Preview'}
+                  {if $wizard.currentStepName == 'Preview'}
                     {if $relatedContactDetails && $relatedContactDetails[$i] != ''}
                             {$mapper[$i]} - {$relatedContactDetails[$i]}
 
                                 {$mapper[$i]}
                             {*/if*}
                         {/if}
-                    {else}
-                        {$form.mapper[$i].html|smarty:nodefaults}
-                    {/if}
+                  {else}
+                    {$mapperField.html|smarty:nodefaults}
+                  {/if}
                 </td>
 
             </tr>
-        {/section}
+        {/foreach}
 
     </table>
   {/strip}
index 56e79ca392405aff3f90809626a4a22fa0cdbc60..2c691a8dfa226821dacff76819ef3fa034ae189b 100644 (file)
@@ -14,6 +14,8 @@
  * File for the CRM_Contact_Import_Form_MapFieldTest class.
  */
 
+use Civi\Api4\UserJob;
+
 /**
  *  Test contact import map field.
  *
@@ -43,20 +45,19 @@ class CRM_Contact_Import_Form_MapFieldTest extends CiviUnitTestCase {
    * @param array $mapper
    * @param array $expecteds
    *
+   * @throws \API_Exception
    * @throws \CRM_Core_Exception
    * @throws \CiviCRM_API3_Exception
    */
-  public function testSubmit($params, $mapper, $expecteds = []) {
-    CRM_Core_DAO::executeQuery('CREATE TABLE IF NOT EXISTS civicrm_import_job_xxx (`nada` text, `first_name` text, `last_name` text, `address` text) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci');
-    $form = $this->getFormObject('CRM_Contact_Import_Form_MapField');
+  public function testSubmit($params, $mapper, $expecteds = []): void {
+    $form = $this->getMapFieldFormObject('CRM_Contact_Import_Form_MapField');
     /* @var CRM_Contact_Import_Form_MapField $form */
     $form->set('contactType', CRM_Import_Parser::CONTACT_INDIVIDUAL);
     $form->_columnNames = ['nada', 'first_name', 'last_name', 'address'];
-    $form->set('importTableName', 'civicrm_import_job_xxx');
     $form->preProcess();
     $form->submit($params, $mapper);
 
-    CRM_Core_DAO::executeQuery("DROP TABLE civicrm_import_job_xxx");
+    CRM_Core_DAO::executeQuery('DROP TABLE civicrm_tmp_d_import_job_xxx');
     if (!empty($expecteds)) {
       foreach ($expecteds as $expected) {
         $result = $this->callAPISuccess($expected['entity'], 'get', array_merge($expected['values'], ['sequential' => 1]));
@@ -124,26 +125,32 @@ class CRM_Contact_Import_Form_MapFieldTest extends CiviUnitTestCase {
   }
 
   /**
-   * Instantiate form object
+   * Instantiate MapField form object
    *
-   * @param string $class
-   * @param array $formValues
-   * @param string $pageName
-   * @param array $searchFormValues
-   *   Values for the search form if the form is a task eg.
-   *   for selected ids 6 & 8:
-   *   [
-   *      'radio_ts' => 'ts_sel',
-   *      'task' => CRM_Member_Task::PDF_LETTER,
-   *      'mark_x_6' => 1,
-   *      'mark_x_8' => 1,
-   *   ]
-   *
-   * @return \CRM_Core_Form
+   * @return \CRM_Contact_Import_Form_MapField
+   * @throws \API_Exception
    * @throws \CRM_Core_Exception
    */
-  public function getFormObject($class, $formValues = [], $pageName = '', $searchFormValues = []) {
-    $form = parent::getFormObject($class);
+  public function getMapFieldFormObject(): CRM_Contact_Import_Form_MapField {
+    CRM_Core_DAO::executeQuery('CREATE TABLE IF NOT EXISTS civicrm_tmp_d_import_job_xxx (`nada` text, `first_name` text, `last_name` text, `address` text) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci');
+    $userJobID = UserJob::create()->setValues([
+      'metadata' => [
+        'submitted_values' => [
+          'dataSource' => 'CRM_Import_DataSource_SQL',
+          'sqlQuery' => 'SELECT * FROM civicrm_tmp_d_import_job_xxx',
+        ],
+      ],
+      'status_id:name' => 'draft',
+      'type_id:name' => 'contact_import',
+    ])->execute()->first()['id'];
+
+    $dataSource = new CRM_Import_DataSource_SQL($userJobID);
+    $params = ['sqlQuery' => 'SELECT * FROM civicrm_tmp_d_import_job_xxx'];
+    $null = NULL;
+    $form = $this->getFormObject('CRM_Contact_Import_Form_MapField');
+    $form->set('user_job_id', $userJobID);
+    $dataSource->postProcess($params, $null, $form);
+
     $contactFields = CRM_Contact_BAO_Contact::importableFields();
     $fields = [];
     foreach ($contactFields as $name => $field) {
@@ -184,9 +191,8 @@ class CRM_Contact_Import_Form_MapFieldTest extends CiviUnitTestCase {
    * @throws \API_Exception
    * @throws \CRM_Core_Exception
    * @throws \CiviCRM_API3_Exception
-   * @throws \Civi\API\Exception\UnauthorizedException
    */
-  public function testLoadSavedMappingDirect() {
+  public function testLoadSavedMappingDirect(): void {
     $this->entity = 'Contact';
     $this->createCustomGroupWithFieldOfType(['title' => 'My Field']);
     $this->setUpMapFieldForm();
@@ -388,7 +394,7 @@ document.forms.MapField['mapper[0][3]'].style.display = 'none';\n",
    * @throws \CRM_Core_Exception
    */
   private function setUpMapFieldForm() {
-    $this->form = $this->getFormObject('CRM_Contact_Import_Form_MapField');
+    $this->form = $this->getMapFieldFormObject();
     $this->form->set('contactType', CRM_Import_Parser::CONTACT_INDIVIDUAL);
   }