diff --git a/modules/backend/behaviors/ImportExportController.php b/modules/backend/behaviors/ImportExportController.php
index 7e83b3ab0..72d407c83 100644
--- a/modules/backend/behaviors/ImportExportController.php
+++ b/modules/backend/behaviors/ImportExportController.php
@@ -2,7 +2,7 @@
use Str;
use Backend\Classes\ControllerBehavior;
-use League\Csv\Writer as CsvWrtier;
+use League\Csv\Writer as CsvWriter;
use League\Csv\Reader as CsvReader;
use ApplicationException;
use Exception;
@@ -86,7 +86,22 @@ class ImportExportController extends ControllerBehavior
public function onImport()
{
- // traceLog(post());
+ try {
+ $model = $this->importGetModel();
+ $matches = post('column_match', []);
+ $sessionKey = $this->importUploadFormWidget->getSessionKey();
+
+ $model->importDataFromColumnMatch($matches, $sessionKey, [
+ 'firstRowTitles' => post('first_row_titles', false)
+ ]);
+
+ $this->vars['importResults'] = $model->getResultStats();
+ }
+ catch (Exception $ex) {
+ $this->controller->handleError($ex);
+ }
+
+ return $this->importExportMakePartial('import_result_form');
}
public function onImportLoadForm()
@@ -151,7 +166,7 @@ class ImportExportController extends ControllerBehavior
$this->vars['importDbColumns'] = $this->getImportDbColumns();
$this->vars['importFileColumns'] = $this->getImportFileColumns();
- // Make these variables to widgets
+ // Make these variables available to widgets
$this->controller->vars += $this->vars;
}
@@ -214,17 +229,9 @@ class ImportExportController extends ControllerBehavior
protected function getImportFilePath()
{
- $model = $this->importGetModel();
- $file = $model
- ->import_file()
- ->withDeferred($this->importUploadFormWidget->getSessionKey())
- ->first();
-
- if (!$file) {
- return null;
- }
-
- return $file->getLocalPath();
+ return $this
+ ->importGetModel()
+ ->getImportFilePath($this->importUploadFormWidget->getSessionKey());
}
public function importIsColumnRequired($columnName)
diff --git a/modules/backend/behaviors/importexportcontroller/assets/js/october.import.js b/modules/backend/behaviors/importexportcontroller/assets/js/october.import.js
index 2e1b1ffe1..0e863db55 100644
--- a/modules/backend/behaviors/importexportcontroller/assets/js/october.import.js
+++ b/modules/backend/behaviors/importexportcontroller/assets/js/october.import.js
@@ -101,7 +101,12 @@
this.processImport = function () {
var $form = $('#importFileColumns').closest('form')
- $form.request('onImport')
+ $form.request('onImport', {
+ success: function(data) {
+ $('#importContainer').html(data.result)
+ $(document).trigger('render')
+ }
+ })
}
}
diff --git a/modules/backend/behaviors/importexportcontroller/partials/_import_result_form.htm b/modules/backend/behaviors/importexportcontroller/partials/_import_result_form.htm
new file mode 100644
index 000000000..018653e60
--- /dev/null
+++ b/modules/backend/behaviors/importexportcontroller/partials/_import_result_form.htm
@@ -0,0 +1,102 @@
+fatalError): ?>
+
+
+
+
+
+
+
Created
+
= $importResults->created ?>
+
+
+
Updated
+
= $importResults->updated ?>
+
+ skippedCount): ?>
+
+
Skipped
+
= $importResults->skippedCount ?>
+
+
+ warningCount): ?>
+
+
Warnings
+
= $importResults->warningCount ?>
+
+
+
+
Errors
+
= $importResults->errorCount ?>
+
+
+
+
+ hasMessages): ?>
+ 'Skipped rows',
+ 'warnings' => 'Warnings',
+ 'errors' => 'Errors',
+ ];
+
+ if (!$importResults->skippedCount) unset($tabs['skipped']);
+ if (!$importResults->warningCount) unset($tabs['warnings']);
+ if (!$importResults->errorCount) unset($tabs['errors']);
+ ?>
+
+
+
+
+
+
+
+
+
+
+
= e($this->fatalError) ?>
+
+
+
+
\ No newline at end of file
diff --git a/modules/backend/lang/en/lang.php b/modules/backend/lang/en/lang.php
index 1a76e8a8c..b470b2c41 100644
--- a/modules/backend/lang/en/lang.php
+++ b/modules/backend/lang/en/lang.php
@@ -187,6 +187,7 @@ return [
'close' => 'Close',
'confirm' => 'Confirm',
'reload' => 'Reload',
+ 'complete' => 'Complete',
'ok' => 'OK',
'or' => 'or',
'confirm_tab_close' => 'Do you really want to close the tab? Unsaved changes will be lost.',
diff --git a/modules/backend/models/ImportModel.php b/modules/backend/models/ImportModel.php
index c62c44172..3d45f1ffb 100644
--- a/modules/backend/models/ImportModel.php
+++ b/modules/backend/models/ImportModel.php
@@ -1,6 +1,7 @@
['System\Models\File']
];
+ protected $resultStats = [
+ 'updated' => 0,
+ 'created' => 0,
+ 'errors' => [],
+ 'warnings' => [],
+ 'skipped' => []
+ ];
+
/**
* Called when data is being imported.
*/
- abstract public function importData();
+ abstract public function importData($results, $sessionKey = null);
+ public function importDataFromColumnMatch($matches, $sessionKey = null, $options = [])
+ {
+ $path = $this->getImportFilePath($sessionKey);
+ $data = $this->processImportData($path, $matches, $options);
+ return $this->importData($data, $sessionKey);
+ }
+
+ /**
+ * Converts column index to database column map to an array containing
+ * database column names and values pulled from the CSV file.
+ * Eg:
+ * [0 => [first_name], 1 => [last_name]]
+ *
+ * Will return:
+ * [first_name => Joe, last_name => Blogs],
+ * [first_name => Harry, last_name => Potter],
+ * [...]
+ *
+ * @return array
+ */
+ protected function processImportData($filePath, $matches, $options)
+ {
+ extract(array_merge([
+ 'firstRowTitles' => true
+ ], $options));
+
+ $reader = CsvReader::createFromPath($filePath);
+
+ if ($firstRowTitles) {
+ $reader->setOffset(1);
+ }
+
+ $result = [];
+ $contents = $reader->fetchAll();
+ foreach ($contents as $row) {
+ $result[] = $this->processImportRow($row, $matches);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Converts a single row of CSV data to the column map.
+ * @return array
+ */
+ protected function processImportRow($rowData, $matches)
+ {
+ $newRow = [];
+
+ foreach ($matches as $columnIndex => $dbNames) {
+ $value = array_get($rowData, $columnIndex);
+ foreach ((array) $dbNames as $dbName) {
+ $newRow[$dbName] = $value;
+ }
+ }
+
+ return $newRow;
+ }
+
+ /**
+ * Returns an attached imported file local path, if available.
+ * @return string
+ */
+ public function getImportFilePath($sessionKey = null)
+ {
+ $file = $this
+ ->import_file()
+ ->withDeferred($sessionKey)
+ ->first();
+
+ if (!$file) {
+ return null;
+ }
+
+ return $file->getLocalPath();
+ }
+
+ //
+ // Result logging
+ //
+
+ public function getResultStats()
+ {
+ $this->resultStats['errorCount'] = count($this->resultStats['errors']);
+ $this->resultStats['warningCount'] = count($this->resultStats['warnings']);
+ $this->resultStats['skippedCount'] = count($this->resultStats['skipped']);
+
+ $this->resultStats['hasMessages'] = (
+ $this->resultStats['errorCount'] > 0 ||
+ $this->resultStats['warningCount'] > 0 ||
+ $this->resultStats['skippedCount'] > 0
+ );
+
+ return (object) $this->resultStats;
+ }
+
+ protected function logUpdated()
+ {
+ $this->resultStats['updated']++;
+ }
+
+ protected function logCreated()
+ {
+ $this->resultStats['created']++;
+ }
+
+ protected function logError($rowIndex, $message)
+ {
+ $this->resultStats['errors'][$rowIndex] = $message;
+ }
+
+ protected function logWarning($rowIndex, $message)
+ {
+ $this->resultStats['warnings'][$rowIndex] = $message;
+ }
+
+ protected function logSkipped($rowIndex, $message)
+ {
+ $this->resultStats['skipped'][$rowIndex] = $message;
+ }
}
\ No newline at end of file