Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Support for Excel File Format to ImportExportController #1277

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"winter/wn-backend-module": "dev-develop",
"winter/wn-cms-module": "dev-develop",
"laravel/framework": "^9.1",
"wikimedia/composer-merge-plugin": "~2.1.0"
"wikimedia/composer-merge-plugin": "~2.1.0",
"phpoffice/phpspreadsheet": "^2.1|^3.6"
},
"require-dev": {
"phpunit/phpunit": "^9.5.8",
Expand Down
49 changes: 38 additions & 11 deletions modules/backend/behaviors/ImportExportController.php
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
<?php namespace Backend\Behaviors;

use Str;
use Lang;
use View;
use Response;
use Backend;
use BackendAuth;
use Backend\Classes\ControllerBehavior;
use ApplicationException;
use Backend\Facades\Backend;
use Backend\Facades\BackendAuth;
use Backend\Behaviors\ImportExportController\TranscodeFilter;
use Backend\Classes\ControllerBehavior;
use Exception;
use Illuminate\Database\Eloquent\MassAssignmentException;
use League\Csv\Reader as CsvReader;
use League\Csv\Writer as CsvWriter;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\View;
use League\Csv\EscapeFormula as CsvEscapeFormula;
use League\Csv\Reader as CsvReader;
use League\Csv\Statement as CsvStatement;
use ApplicationException;
use League\Csv\Writer as CsvWriter;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\IReader;
use SplTempFileObject;
use Exception;
use Winter\Storm\Support\Str;

/**
* Adds features for importing and exporting data.
Expand Down Expand Up @@ -324,6 +326,17 @@ protected function getImportFileColumns()
return null;
}

$fileFormat = post('format_preset');

return match ($fileFormat) {
'standard', 'custom' => $this->getImportFileColumnsFromCsv($path),
'excel' => $this->getImportFileColumnsFromSpreadsheet($path),
default => throw new ApplicationException('Unsupported file format'),
};
}

protected function getImportFileColumnsFromCsv(string $path)
{
$reader = $this->createCsvReader($path);
$firstRow = $reader->fetchOne(0);

Expand All @@ -343,6 +356,20 @@ protected function getImportFileColumns()
return $firstRow;
}

protected function getImportFileColumnsFromSpreadsheet(string $path)
{
$spreadsheet = IOFactory::load($path, IReader::READ_DATA_ONLY, [
IOFactory::READER_XLSX,
IOFactory::READER_XLS,
IOFactory::READER_ODS,
]);

$sheet = $spreadsheet->getActiveSheet();
$data = $sheet->toArray();

return $data[0];
}

/**
* Get the index offset to add to the reported row number in status messages
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ fields:
type: fileupload
mode: file
span: left
fileTypes: csv
fileTypes: csv, xls, xlsx, ods
useCaption: false

format_preset:
Expand All @@ -22,6 +22,7 @@ fields:
options:
standard: backend::lang.import_export.standard_format
custom: backend::lang.import_export.custom_format
excel: backend::lang.import_export.excel_format
span: right

format_delimiter:
Expand Down Expand Up @@ -92,4 +93,4 @@ fields:

step3_section:
label: backend::lang.import_export.set_import_options
type: section
type: section
5 changes: 3 additions & 2 deletions modules/backend/lang/en/lang.php
Original file line number Diff line number Diff line change
Expand Up @@ -529,8 +529,9 @@
'set_import_options' => '3. Set import options',
'export_output_format' => '1. Export output format',
'file_format' => 'File format',
'standard_format' => 'Standard format',
'custom_format' => 'Custom format',
'standard_format' => 'CSV Standard',
'custom_format' => 'CSV Custom',
'excel_format' => 'Excel (xls, xlsx, ods)',
'delimiter_char' => 'Delimiter character',
'enclosure_char' => 'Enclosure character',
'escape_char' => 'Escape character',
Expand Down
43 changes: 40 additions & 3 deletions modules/backend/models/ImportModel.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
<?php namespace Backend\Models;

use Backend\Behaviors\ImportExportController\TranscodeFilter;
use Str;
use Lang;
use Model;
use Illuminate\Support\Facades\Lang;
use League\Csv\Reader as CsvReader;
use League\Csv\Statement as CsvStatement;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\IReader;
use Winter\Storm\Database\Model;
use Winter\Storm\Support\Facades\File;
use Winter\Storm\Support\Str;

/**
* Model used for importing data
Expand Down Expand Up @@ -104,6 +107,17 @@ protected function processImportData($filePath, $matches, $options)

$options = array_merge($defaultOptions, $options);

$fileFormat = post('format_preset');

return match ($fileFormat) {
'standard', 'custom' => $this->processImportDataAsCsv($filePath, $matches, $options),
'excel' => $this->processImportDataFromSpreadsheet($filePath, $matches, $options),
default => throw new ApplicationException('Unsupported file format'),
};
}

protected function processImportDataAsCsv(string $filePath, array $matches, array $options): array
{
/*
* Read CSV
*/
Expand Down Expand Up @@ -153,6 +167,29 @@ protected function processImportData($filePath, $matches, $options)
return $result;
}

protected function processImportDataFromSpreadsheet(string $filePath, array $matches, array $options): array
{
$spreadsheet = IOFactory::load($filePath, IReader::READ_DATA_ONLY, [
IOFactory::READER_XLSX,
IOFactory::READER_XLS,
IOFactory::READER_ODS,
]);

$sheet = $spreadsheet->getActiveSheet();

$sheetData = $sheet->toArray();
if ($options['firstRowTitles']) {
$sheetData = array_slice($sheetData, 1);
}

$result = [];
foreach ($sheetData as $rowData) {
$result[] = $this->processImportRow($rowData, $matches);
}

return $result;
}

/**
* Converts a single row of CSV data to the column map.
* @return array
Expand Down
Loading