NUM_ROWS_TO_INSERT = 100;
/**
- * Provides information about the data source.
+ * Form fields declared for this datasource.
*
- * @return array
- * collection of info about this data source
+ * @var string[]
*/
- public function getInfo() {
- return ['title' => ts('Comma-Separated Values (CSV)')];
- }
+ protected $submittableFields = ['skipColumnHeader', 'uploadField'];
/**
- * Set variables up before form is built.
+ * Provides information about the data source.
*
- * @param CRM_Core_Form $form
+ * @return array
+ * collection of info about this data source
*/
- public function preProcess(&$form) {
+ public function getInfo(): array {
+ return ['title' => ts('Comma-Separated Values (CSV)')];
}
/**
public function buildQuickForm(&$form) {
$form->add('hidden', 'hidden_dataSource', 'CRM_Import_DataSource_CSV');
- $config = CRM_Core_Config::singleton();
-
- $uploadFileSize = CRM_Utils_Number::formatUnitSize($config->maxFileSize . 'm', TRUE);
+ $uploadFileSize = CRM_Utils_Number::formatUnitSize(Civi::settings()->get('maxFileSize') . 'm', TRUE);
//Fetch uploadFileSize from php_ini when $config->maxFileSize is set to "no limit".
if (empty($uploadFileSize)) {
$uploadFileSize = CRM_Utils_Number::formatUnitSize(ini_get('upload_max_filesize'), TRUE);
}
/**
- * Process the form submission.
- *
- * @param array $params
- * @param string $db
- * @param \CRM_Core_Form $form
+ * Initialize the datasource, based on the submitted values stored in the user job.
*
+ * @throws \API_Exception
* @throws \CRM_Core_Exception
*/
- public function postProcess(&$params, &$db, &$form) {
- $file = $params['uploadFile']['name'];
- $result = self::_CsvToTable($db,
- $file,
- CRM_Utils_Array::value('skipColumnHeader', $params, FALSE),
- CRM_Utils_Array::value('import_table_name', $params),
- CRM_Utils_Array::value('fieldSeparator', $params, ',')
+ public function initialize(): void {
+ $result = self::_CsvToTable(
+ $this->getSubmittedValue('uploadFile')['name'],
+ $this->getSubmittedValue('skipColumnHeader'),
+ $this->getSubmittedValue('fieldSeparator') ?? ','
);
+ $this->addTrackingFieldsToTable($result['import_table_name']);
- $form->set('originalColHeader', CRM_Utils_Array::value('original_col_header', $result));
-
- $table = $result['import_table_name'];
- $importJob = new CRM_Contact_Import_ImportJob($table);
- $form->set('importTableName', $importJob->getTableName());
+ $this->updateUserJobMetadata('DataSource', [
+ 'table_name' => $result['import_table_name'],
+ 'column_headers' => $this->getSubmittedValue('skipColumnHeader') ? $result['column_headers'] : [],
+ 'number_of_columns' => $result['number_of_columns'],
+ ]);
}
/**
* Create a table that matches the CSV file and populate it with the file's contents
*
- * @param object $db
- * Handle to the database connection.
* @param string $file
* File name to load.
* @param bool $headers
* Whether the first row contains headers.
- * @param string $tableName
- * Name of table from which data imported.
* @param string $fieldSeparator
* Character that separates the various columns in the file.
*
* @throws \CRM_Core_Exception
*/
private static function _CsvToTable(
- &$db,
$file,
$headers = FALSE,
- $tableName = NULL,
$fieldSeparator = ','
) {
$result = [];
// create the column names from the CSV header or as col_0, col_1, etc.
if ($headers) {
//need to get original headers.
- $result['original_col_header'] = $firstrow;
+ $result['column_headers'] = $firstrow;
$strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower';
$columns = array_map($strtolower, $firstrow);
}
}
- if ($tableName) {
- CRM_Core_DAO::executeQuery("DROP TABLE IF EXISTS $tableName");
- }
$table = CRM_Utils_SQL_TempTable::build()->setDurable();
$tableName = $table->getName();
CRM_Core_DAO::executeQuery("DROP TABLE IF EXISTS $tableName");
if (count($row) != $numColumns) {
continue;
}
+ // A blank line will be array(0 => NULL)
+ if ($row === [NULL]) {
+ continue;
+ }
if (!$first) {
$sql .= ', ';
$first = FALSE;
// CRM-17859 Trim non-breaking spaces from columns.
- $row = array_map(
- function($string) {
- return trim($string, chr(0xC2) . chr(0xA0));
- }, $row);
+ $row = array_map(['CRM_Import_DataSource_CSV', 'trimNonBreakingSpaces'], $row);
$row = array_map(['CRM_Core_DAO', 'escapeString'], $row);
$sql .= "('" . implode("', '", $row) . "')";
$count++;
//get the import tmp table name.
$result['import_table_name'] = $tableName;
-
+ $result['number_of_columns'] = $numColumns;
return $result;
}
+ /**
+ * Trim non-breaking spaces in a multibyte-safe way.
+ * See also dev/core#2127 - avoid breaking strings ending in à or any other
+ * unicode character sharing the same 0xA0 byte as a non-breaking space.
+ *
+ * @param string $string
+ * @return string The trimmed string
+ */
+ public static function trimNonBreakingSpaces(string $string): string {
+ $encoding = mb_detect_encoding($string, NULL, TRUE);
+ if ($encoding === FALSE) {
+ // This could mean a couple things. One is that the string is
+ // ASCII-encoded but contains a non-breaking space, which causes
+ // php to fail to detect the encoding. So let's just do what we
+ // did before which works in that situation and is at least no
+ // worse in other situations.
+ return trim($string, chr(0xC2) . chr(0xA0));
+ }
+ elseif ($encoding !== 'UTF-8') {
+ $string = mb_convert_encoding($string, 'UTF-8', [$encoding]);
+ }
+ return preg_replace("/^(\u{a0})+|(\u{a0})+$/", '', $string);
+ }
+
}