dev/core#3651 dev/core#1337 Fix failure to show last column data in output, spaces...
authorEileen McNaughton <emcnaughton@wikimedia.org>
Sat, 11 Jun 2022 23:36:09 +0000 (11:36 +1200)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Sun, 12 Jun 2022 00:23:51 +0000 (12:23 +1200)
CRM/Import/DataSource.php
CRM/Import/DataSource/CSV.php
CRM/Import/DataSource/SQL.php
CRM/Import/Forms.php

index 3b4ed98785584951cf9955a5cbffcc0c85e5b528..df8ea13d12664a4d455b908c5f0b0b06040814ef 100644 (file)
@@ -67,6 +67,30 @@ abstract class CRM_Import_DataSource {
    */
   private $statuses = [];
 
+  /**
+   * Fields to select.
+   *
+   * @var array
+   */
+  private $selectFields;
+
+  /**
+   * @return array|null
+   */
+  public function getSelectFields(): ?array {
+    return $this->selectFields;
+  }
+
+  /**
+   * @param array $selectFields
+   *
+   * @return CRM_Import_DataSource
+   */
+  public function setSelectFields(array $selectFields): CRM_Import_DataSource {
+    $this->selectFields = $selectFields;
+    return $this;
+  }
+
   /**
    * Current row.
    *
@@ -537,13 +561,20 @@ abstract class CRM_Import_DataSource {
    * @throws \CRM_Core_Exception
    */
   private function instantiateQueryObject(): void {
-    $query = 'SELECT * FROM ' . $this->getTableName() . ' ' . $this->getStatusClause();
+    $query = 'SELECT ' . $this->getSelectClause() . ' FROM ' . $this->getTableName() . ' ' . $this->getStatusClause();
     if ($this->limit) {
       $query .= ' LIMIT ' . $this->limit . ($this->offset ? (' OFFSET ' . $this->offset) : NULL);
     }
     $this->queryResultObject = CRM_Core_DAO::executeQuery($query);
   }
 
+  /**
+   * @return string
+   */
+  private function getSelectClause(): string {
+    return $this->getSelectFields() ? implode(', ', $this->getSelectFields()) : '*';
+  }
+
   /**
    * Get the mapping of constants to database status codes.
    *
index f084d65c73976f070c7573d2493a608ed4d572ee..4712ce30e91e468b925ef16d8fc333f06c484c6b 100644 (file)
@@ -124,7 +124,6 @@ class CRM_Import_DataSource_CSV extends CRM_Import_DataSource {
     }
 
     $firstrow = fgetcsv($fd, 0, $fieldSeparator);
-    $result['column_headers'] = array_fill(0, count($firstrow), '');
     // create the column names from the CSV header or as col_0, col_1, etc.
     if ($headers) {
       //need to get original headers.
@@ -169,8 +168,9 @@ class CRM_Import_DataSource_CSV extends CRM_Import_DataSource {
     else {
       $columns = [];
       foreach ($firstrow as $i => $_) {
-        $columns[] = "col_$i";
+        $columns[] = "column_$i";
       }
+      $result['column_headers'] = $columns;
     }
 
     $table = CRM_Utils_SQL_TempTable::build()->setDurable();
index cfd3c6f727ba93619080c1298745d410768d50eb..78b20839f9be3f4bb87f7a2799c143d1076af521 100644 (file)
@@ -92,7 +92,17 @@ class CRM_Import_DataSource_SQL extends CRM_Import_DataSource {
 
     $columnNames = [];
     while ($columnsResult->fetch()) {
-      $columnNames[] = $columnsResult->Field;
+      if (strpos($columnsResult->Field, ' ') !== FALSE) {
+        // Remove spaces as the Database object does this
+        // $keys = str_replace(array(".", " "), "_", array_keys($array));
+        // https://lab.civicrm.org/dev/core/-/issues/1337
+        $usableColumnName = str_replace(' ', '_', $columnsResult->Field);
+        CRM_Core_DAO::executeQuery('ALTER TABLE ' . $tableName . ' CHANGE `' . $columnsResult->Field . '` ' . $usableColumnName . ' ' . $columnsResult->Type);
+        $columnNames[] = $usableColumnName;
+      }
+      else {
+        $columnNames[] = $columnsResult->Field;
+      }
     }
 
     $this->addTrackingFieldsToTable($tableName);
index f07a203297e3c32b456dd77d5e07ec25e850b718..b2f96352e4cfe06cf232d361c006df5eb987ae48 100644 (file)
@@ -456,6 +456,35 @@ class CRM_Import_Forms extends CRM_Core_Form {
     return $this->getDataSourceObject()->setLimit($limit)->setStatuses($statuses)->getRows();
   }
 
+  /**
+   * Get the datasource rows ready for csv output.
+   *
+   * @param array $statuses
+   * @param int $limit
+   *
+   * @return array
+   * @throws \API_Exception
+   * @throws \CRM_Core_Exception
+   */
+  protected function getOutputRows($statuses = [], int $limit = 0) {
+    $statuses = (array) $statuses;
+    return $this->getDataSourceObject()->setLimit($limit)->setStatuses($statuses)
+      ->setSelectFields(array_merge(['_id', '_status_message'], $this->getColumnHeaders()))
+      ->setStatuses($statuses)->getRows();
+  }
+
+  /**
+   * Get the column headers for the output csv.
+   *
+   * @return array
+   */
+  protected function getOutputColumnsHeaders(): array {
+    $headers = $this->getColumnHeaders();
+    array_unshift($headers, ts('Reason'));
+    array_unshift($headers, ts('Line Number'));
+    return $headers;
+  }
+
   /**
    * Get the number of rows with the specified status.
    *
@@ -492,16 +521,11 @@ class CRM_Import_Forms extends CRM_Core_Form {
 
     $form->getUserJob();
     $writer = Writer::createFromFileObject(new SplTempFileObject());
-    $headers = $form->getColumnHeaders();
-    if ($headers) {
-      array_unshift($headers, ts('Reason'));
-      array_unshift($headers, ts('Line Number'));
-      $writer->insertOne($headers);
-    }
-    $writer->addFormatter(['CRM_Import_Forms', 'reorderOutput']);
+    $headers = $form->getOutputColumnsHeaders();
+    $writer->insertOne($headers);
     // Note this might be more inefficient that iterating the result
     // set & doing insertOne - possibly something to explore later.
-    $writer->insertAll($form->getDataRows($status));
+    $writer->insertAll($form->getOutputRows($status));
 
     CRM_Utils_System::setHttpHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');
     CRM_Utils_System::setHttpHeader('Content-Description', 'File Transfer');
@@ -510,28 +534,6 @@ class CRM_Import_Forms extends CRM_Core_Form {
     CRM_Utils_System::civiExit();
   }
 
-  /**
-   * When outputting the row as a csv, more the last 2 rows to the start.
-   *
-   * This is because the id and status message fields are at the end. It may make sense
-   * to move them to the start later, when order code cleanup has happened...
-   *
-   * @param array $record
-   */
-  public static function reorderOutput(array $record): array {
-    $rowNumber = array_pop($record);
-    $message = array_pop($record);
-    // Also pop off the status - but we are not going to use this at this stage.
-    array_pop($record);
-    // Related entities
-    array_pop($record);
-    // Entity_id
-    array_pop($record);
-    array_unshift($record, $message);
-    array_unshift($record, $rowNumber);
-    return $record;
-  }
-
   /**
    * Get the url to download the relevant csv file.
    * @param string $status
@@ -597,7 +599,7 @@ class CRM_Import_Forms extends CRM_Core_Form {
     $this->_columnNames = $this->getColumnHeaders();
     $this->_dataValues = array_values($this->getDataRows([], 2));
     $this->assign('columnNames', $this->getColumnHeaders());
-    $this->assign('showColumnNames', $this->getSubmittedValue('skipColumnHeader'));
+    $this->assign('showColumnNames', $this->getSubmittedValue('skipColumnHeader') || $this->getSubmittedValue('dataSource') !== 'CRM_Import_DataSource');
     $this->assign('highlightedFields', $this->getHighlightedFields());
     $this->assign('columnCount', $this->_columnCount);
     $this->assign('dataValues', $this->_dataValues);