Tidy up some logic, restore firstRowTitles setting

Refs #1856
This commit is contained in:
Samuel Georges 2016-03-26 14:10:05 +11:00
parent 2a60e34558
commit a035acdc2c
5 changed files with 135 additions and 128 deletions

View File

@ -7,7 +7,7 @@ use Response;
use Backend; use Backend;
use BackendAuth; use BackendAuth;
use Backend\Classes\ControllerBehavior; use Backend\Classes\ControllerBehavior;
use Backend\Classes\StreamFilterTranscode; use Backend\Behaviors\ImportExportController\TranscodeFilter;
use League\Csv\Reader as CsvReader; use League\Csv\Reader as CsvReader;
use League\Csv\Writer as CsvWriter; use League\Csv\Writer as CsvWriter;
use ApplicationException; use ApplicationException;
@ -175,20 +175,14 @@ class ImportExportController extends ControllerBehavior
try { try {
$model = $this->importGetModel(); $model = $this->importGetModel();
$matches = post('column_match', []); $matches = post('column_match', []);
$importOptions = [
'sessionKey' => $this->importUploadFormWidget->getSessionKey()
];
if ($optionData = post('ImportOptions')) { if ($optionData = post('ImportOptions')) {
$model->fill($optionData); $model->fill($optionData);
} }
if (post('format_preset') == 'custom') { $importOptions = $this->getFormatOptionsFromPost();
$importOptions['delimiter'] = post('format_delimiter'); $importOptions['sessionKey'] = $this->importUploadFormWidget->getSessionKey();
$importOptions['enclosure'] = post('format_enclosure'); $importOptions['firstRowTitles'] = post('first_row_titles', false);
$importOptions['escape'] = post('format_escape');
$importOptions['encoding'] = post('format_encoding');
}
$model->import($matches, $importOptions); $model->import($matches, $importOptions);
@ -310,8 +304,10 @@ class ImportExportController extends ControllerBehavior
}); });
} }
// Prevents unfriendly error to be thrown due to bad encoding at response time /*
if (false === json_encode($firstRow)) { * Prevents unfriendly error to be thrown due to bad encoding at response time.
*/
if (json_encode($firstRow) === false) {
throw new ApplicationException(Lang::get('backend::lang.import_export.encoding_not_supported_error')); throw new ApplicationException(Lang::get('backend::lang.import_export.encoding_not_supported_error'));
} }
@ -395,19 +391,13 @@ class ImportExportController extends ControllerBehavior
try { try {
$model = $this->exportGetModel(); $model = $this->exportGetModel();
$columns = $this->processExportColumnsFromPost(); $columns = $this->processExportColumnsFromPost();
$exportOptions = [
'sessionKey' => $this->exportFormatFormWidget->getSessionKey()
];
if ($optionData = post('ExportOptions')) { if ($optionData = post('ExportOptions')) {
$model->fill($optionData); $model->fill($optionData);
} }
if (post('format_preset') == 'custom') { $exportOptions = $this->getFormatOptionsFromPost();
$exportOptions['delimiter'] = post('format_delimiter'); $exportOptions['sessionKey'] = $this->exportFormatFormWidget->getSessionKey();
$exportOptions['enclosure'] = post('format_enclosure');
$exportOptions['escape'] = post('format_escape');
}
$reference = $model->export($columns, $exportOptions); $reference = $model->export($columns, $exportOptions);
$fileUrl = $this->controller->actionUrl( $fileUrl = $this->controller->actionUrl(
@ -705,7 +695,6 @@ class ImportExportController extends ControllerBehavior
return $this->controller->actionUrl($type); return $this->controller->actionUrl($type);
} }
/** /**
* Create a new CSV reader with options selected by the user * Create a new CSV reader with options selected by the user
* @param string $path * @param string $path
@ -715,14 +704,7 @@ class ImportExportController extends ControllerBehavior
protected function createCsvReader($path) protected function createCsvReader($path)
{ {
$reader = CsvReader::createFromPath($path); $reader = CsvReader::createFromPath($path);
$options = $this->getFormatOptionsFromPost();
if (post('format_preset') == 'custom') {
$options = [
'delimiter' => post('format_delimiter'),
'enclosure' => post('format_enclosure'),
'escape' => post('format_escape'),
'encoding' => post('format_encoding')
];
if ($options['delimiter'] !== null) { if ($options['delimiter'] !== null) {
$reader->setDelimiter($options['delimiter']); $reader->setDelimiter($options['delimiter']);
@ -736,18 +718,45 @@ class ImportExportController extends ControllerBehavior
$reader->setEscape($options['escape']); $reader->setEscape($options['escape']);
} }
if ($options['encoding'] !== null) { if (
if ($reader->isActiveStreamFilter()) { $options['encoding'] !== null &&
$reader->isActiveStreamFilter()
) {
$reader->appendStreamFilter(sprintf( $reader->appendStreamFilter(sprintf(
'%s%s:%s', '%s%s:%s',
StreamFilterTranscode::FILTER_NAME, TranscodeFilter::FILTER_NAME,
strtolower($options['encoding']), strtolower($options['encoding']),
'utf-8' 'utf-8'
)); ));
} }
}
}
return $reader; return $reader;
} }
/**
* Returns the file format options from postback. This method
* can be used to define presets.
* @return array
*/
protected function getFormatOptionsFromPost()
{
$presetMode = post('format_preset');
$options = [
'delimiter' => null,
'enclosure' => null,
'escape' => null,
'encoding' => null
];
if ($presetMode == 'custom') {
$options['delimiter'] = post('format_delimiter');
$options['enclosure'] = post('format_enclosure');
$options['escape'] = post('format_escape');
$options['encoding'] = post('format_encoding');
}
return $options;
}
} }

View File

@ -0,0 +1,69 @@
<?php namespace Backend\Behaviors\ImportExportController;
use php_user_filter;
stream_filter_register(StreamFilterTranscode::FILTER_NAME . "*", StreamFilterTranscode::class);
/**
* Transcode stream filter.
*
* Convert CSV source files from one encoding to another.
*/
class TranscodeFilter extends php_user_filter
{
const FILTER_NAME = 'october.csv.transcode.';
protected $encodingFrom = 'auto';
protected $encodingTo;
public function filter($in, $out, &$consumed, $closing)
{
while ($resource = stream_bucket_make_writeable($in)) {
$resource->data = @mb_convert_encoding(
$resource->data,
$this->encodingTo,
$this->encodingFrom
);
$consumed += $resource->datalen;
stream_bucket_append($out, $resource);
}
return PSFS_PASS_ON;
}
public function onCreate()
{
if (strpos($this->filtername, self::FILTER_NAME) !== 0) {
return false;
}
$params = substr($this->filtername, strlen(self::FILTER_NAME));
if (!preg_match('/^([-\w]+)(:([-\w]+))?$/', $params, $matches)) {
return false;
}
if (isset($matches[1])) {
$this->encodingFrom = $matches[1];
}
$this->encodingTo = mb_internal_encoding();
if (isset( $matches[3] )) {
$this->encodingTo = $matches[3];
}
$this->params['locale'] = setlocale(LC_CTYPE, '0');
if (stripos($this->params['locale'], 'UTF-8') === false) {
setlocale(LC_CTYPE, 'en_US.UTF-8');
}
return true;
}
public function onClose()
{
setlocale(LC_CTYPE, $this->params['locale']);
}
}

View File

@ -1,71 +0,0 @@
<?php namespace Backend\Classes;
use php_user_filter;
// Register the class for it to be usable by the CSV Lib
stream_filter_register(StreamFilterTranscode::FILTER_NAME . "*", StreamFilterTranscode::class);
/**
* A universal transcode stream filter.
* Used by the backend import model to convert source file from one encoding to another.
* The system must support both source and target encoding encoding.
*
* @credits https://github.com/thephpleague/csv/blob/master/examples/lib/FilterTranscode.php
* @package october\backend
*/
class StreamFilterTranscode extends php_user_filter
{
const FILTER_NAME = 'convert.transcode.';
private $encoding_from = 'auto';
private $encoding_to;
public function onCreate()
{
if (strpos($this->filtername, self::FILTER_NAME) !== 0) {
return false;
}
$params = substr($this->filtername, strlen(self::FILTER_NAME));
if ( ! preg_match('/^([-\w]+)(:([-\w]+))?$/', $params, $matches)) {
return false;
}
if (isset( $matches[1] )) {
$this->encoding_from = $matches[1];
}
$this->encoding_to = mb_internal_encoding();
if (isset( $matches[3] )) {
$this->encoding_to = $matches[3];
}
$this->params['locale'] = setlocale(LC_CTYPE, '0');
if (stripos($this->params['locale'], 'UTF-8') === false) {
setlocale(LC_CTYPE, 'en_US.UTF-8');
}
return true;
}
public function onClose()
{
setlocale(LC_CTYPE, $this->params['locale']);
}
public function filter($in, $out, &$consumed, $closing)
{
while ($res = stream_bucket_make_writeable($in)) {
$res->data = @mb_convert_encoding($res->data, $this->encoding_to, $this->encoding_from);
$consumed += $res->datalen;
stream_bucket_append($out, $res);
}
return PSFS_PASS_ON;
}
}

View File

@ -16,7 +16,6 @@ use SplTempFileObject;
*/ */
abstract class ExportModel extends Model abstract class ExportModel extends Model
{ {
/** /**
* Called when data is being exported. * Called when data is being exported.
* The return value should be an array in the format of: * The return value should be an array in the format of:
@ -202,5 +201,4 @@ abstract class ExportModel extends Model
return implode($delimeter, $newData); return implode($delimeter, $newData);
} }
} }

View File

@ -1,5 +1,6 @@
<?php namespace Backend\Models; <?php namespace Backend\Models;
use Lang;
use Model; use Model;
use League\Csv\Reader as CsvReader; use League\Csv\Reader as CsvReader;
@ -179,7 +180,8 @@ abstract class ImportModel extends Model
$file = $this $file = $this
->import_file() ->import_file()
->withDeferred($sessionKey) ->withDeferred($sessionKey)
->first(); ->first()
;
if (!$file) { if (!$file) {
return null; return null;
@ -195,7 +197,7 @@ abstract class ImportModel extends Model
*/ */
public function getFormatEncodingOptions() public function getFormatEncodingOptions()
{ {
return \Lang::get('backend::lang.import_export.encodings'); return Lang::get('backend::lang.import_export.encodings');
} }
// //