Implement exporting function modeled after import function
This commit is contained in:
parent
5be21f6231
commit
d0742653d1
|
|
@ -3,7 +3,6 @@
|
|||
use Str;
|
||||
use Lang;
|
||||
use Backend\Classes\ControllerBehavior;
|
||||
use League\Csv\Writer as CsvWriter;
|
||||
use League\Csv\Reader as CsvReader;
|
||||
use ApplicationException;
|
||||
use Exception;
|
||||
|
|
@ -44,10 +43,35 @@ class ImportExportController extends ControllerBehavior
|
|||
protected $importUploadFormWidget;
|
||||
|
||||
/**
|
||||
* @var Backend\Classes\WidgetBase Reference to the widget used for specifing import options.
|
||||
* @var Backend\Classes\WidgetBase Reference to the widget used for specifying import options.
|
||||
*/
|
||||
protected $importOptionsFormWidget;
|
||||
|
||||
/**
|
||||
* @var Model Export model
|
||||
*/
|
||||
public $exportModel;
|
||||
|
||||
/**
|
||||
* @var array Export column configuration.
|
||||
*/
|
||||
public $exportColumns;
|
||||
|
||||
/**
|
||||
* @var string File name used for export output.
|
||||
*/
|
||||
protected $exportFileName = 'export.csv';
|
||||
|
||||
/**
|
||||
* @var Backend\Classes\WidgetBase Reference to the widget used for standard export options.
|
||||
*/
|
||||
protected $exportFormatFormWidget;
|
||||
|
||||
/**
|
||||
* @var Backend\Classes\WidgetBase Reference to the widget used for custom export options.
|
||||
*/
|
||||
protected $exportOptionsFormWidget;
|
||||
|
||||
/**
|
||||
* Behavior constructor
|
||||
* @param Backend\Classes\Controller $controller
|
||||
|
|
@ -57,13 +81,22 @@ class ImportExportController extends ControllerBehavior
|
|||
parent::__construct($controller);
|
||||
|
||||
$this->addJs('js/october.import.js', 'core');
|
||||
$this->addJs('js/october.export.js', 'core');
|
||||
$this->addCss('css/import.css', 'core');
|
||||
$this->addCss('css/export.css', 'core');
|
||||
|
||||
/*
|
||||
* Build configuration
|
||||
*/
|
||||
$this->config = $this->makeConfig($controller->importExportConfig, $this->requiredConfig);
|
||||
|
||||
/*
|
||||
* Process config
|
||||
*/
|
||||
if ($exportFileName = $this->getConfig('export[fileName]')) {
|
||||
$this->exportFileName = $exportFileName;
|
||||
}
|
||||
|
||||
/*
|
||||
* Import form widgets
|
||||
*/
|
||||
|
|
@ -75,6 +108,16 @@ class ImportExportController extends ControllerBehavior
|
|||
$this->importOptionsFormWidget->bindToController();
|
||||
}
|
||||
|
||||
/*
|
||||
* Export form widgets
|
||||
*/
|
||||
if ($this->exportFormatFormWidget = $this->makeExportFormatFormWidget()) {
|
||||
$this->exportFormatFormWidget->bindToController();
|
||||
}
|
||||
|
||||
if ($this->exportOptionsFormWidget = $this->makeExportOptionsFormWidget()) {
|
||||
$this->exportOptionsFormWidget->bindToController();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -86,12 +129,23 @@ class ImportExportController extends ControllerBehavior
|
|||
$this->controller->pageTitle = $this->controller->pageTitle
|
||||
?: Lang::get($this->getConfig('import[title]', 'Import records'));
|
||||
|
||||
$this->prepareVars();
|
||||
$this->prepareImportVars();
|
||||
}
|
||||
|
||||
public function export()
|
||||
{
|
||||
// TBA
|
||||
$this->controller->pageTitle = $this->controller->pageTitle
|
||||
?: Lang::get($this->getConfig('export[title]', 'Export records'));
|
||||
|
||||
$this->prepareExportVars();
|
||||
}
|
||||
|
||||
public function download($name, $outputName = null)
|
||||
{
|
||||
$this->controller->pageTitle = $this->controller->pageTitle
|
||||
?: Lang::get($this->getConfig('export[title]', 'Export records'));
|
||||
|
||||
return $this->exportGetModel()->download($name, $outputName);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -103,13 +157,13 @@ class ImportExportController extends ControllerBehavior
|
|||
try {
|
||||
$model = $this->importGetModel();
|
||||
$matches = post('column_match', []);
|
||||
$sessionKey = $this->importUploadFormWidget->getSessionKey();
|
||||
|
||||
if ($optionData = post('ImportOptions')) {
|
||||
$model->fill($optionData);
|
||||
}
|
||||
|
||||
$model->importDataFromColumnMatch($matches, $sessionKey, [
|
||||
$model->import($matches, [
|
||||
'sessionKey' => $this->importUploadFormWidget->getSessionKey(),
|
||||
'firstRowTitles' => post('first_row_titles', false)
|
||||
]);
|
||||
|
||||
|
|
@ -178,7 +232,7 @@ class ImportExportController extends ControllerBehavior
|
|||
* Prepares the view data.
|
||||
* @return void
|
||||
*/
|
||||
public function prepareVars()
|
||||
public function prepareImportVars()
|
||||
{
|
||||
$this->vars['importUploadFormWidget'] = $this->importUploadFormWidget;
|
||||
$this->vars['importOptionsFormWidget'] = $this->importOptionsFormWidget;
|
||||
|
|
@ -196,12 +250,7 @@ class ImportExportController extends ControllerBehavior
|
|||
|
||||
public function importGetModel()
|
||||
{
|
||||
if ($this->importModel !== null) {
|
||||
return $this->importModel;
|
||||
}
|
||||
|
||||
$modelClass = $this->getConfig('import[modelClass]');
|
||||
return $this->importModel = new $modelClass;
|
||||
return $this->getModelForType('import');
|
||||
}
|
||||
|
||||
protected function getImportDbColumns()
|
||||
|
|
@ -233,6 +282,10 @@ class ImportExportController extends ControllerBehavior
|
|||
|
||||
protected function makeImportUploadFormWidget()
|
||||
{
|
||||
if (!$this->getConfig('import')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$widgetConfig = $this->makeConfig('~/modules/backend/behaviors/importexportcontroller/partials/fields_import.yaml');
|
||||
$widgetConfig->model = $this->importGetModel();
|
||||
$widgetConfig->alias = 'importUploadForm';
|
||||
|
|
@ -248,21 +301,14 @@ class ImportExportController extends ControllerBehavior
|
|||
|
||||
protected function makeImportOptionsFormWidget()
|
||||
{
|
||||
if ($fieldConfig = $this->getConfig('import[form]')) {
|
||||
$widgetConfig = $this->makeConfig($fieldConfig);
|
||||
$widgetConfig->model = $this->importGetModel();
|
||||
$widgetConfig->alias = 'importOptionsForm';
|
||||
$widgetConfig->arrayName = 'ImportOptions';
|
||||
$widget = $this->makeOptionsFormWidgetForType('import');
|
||||
|
||||
$widget = $this->makeWidget('Backend\Widgets\Form', $widgetConfig);
|
||||
return $widget;
|
||||
}
|
||||
elseif ($this->importUploadFormWidget) {
|
||||
if (!$widget && $this->importUploadFormWidget) {
|
||||
$stepSection = $this->importUploadFormWidget->getField('step3_section');
|
||||
$stepSection->hidden = true;
|
||||
}
|
||||
|
||||
return null;
|
||||
return $widget;
|
||||
}
|
||||
|
||||
protected function getImportFilePath()
|
||||
|
|
@ -302,10 +348,136 @@ class ImportExportController extends ControllerBehavior
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Exporting AJAX
|
||||
//
|
||||
|
||||
public function onExport()
|
||||
{
|
||||
try {
|
||||
$model = $this->exportGetModel();
|
||||
$columns = $this->processExportColumnsFromPost();
|
||||
$exportOptions = [
|
||||
'sessionKey' => $this->exportFormatFormWidget->getSessionKey()
|
||||
];
|
||||
|
||||
if ($optionData = post('ExportOptions')) {
|
||||
$model->fill($optionData);
|
||||
}
|
||||
|
||||
if (post('format_preset') == 'custom') {
|
||||
$exportOptions['delimiter'] = post('format_delimiter');
|
||||
$exportOptions['enclosure'] = post('format_enclosure');
|
||||
$exportOptions['escape'] = post('format_escape');
|
||||
}
|
||||
|
||||
$reference = $model->export($columns, $exportOptions);
|
||||
|
||||
$this->vars['fileUrl'] = $this->controller->actionUrl(
|
||||
'download',
|
||||
$reference.'/'.$this->exportFileName
|
||||
);
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
$this->controller->handleError($ex);
|
||||
}
|
||||
|
||||
return $this->importExportMakePartial('export_result_form');
|
||||
}
|
||||
|
||||
public function onExportLoadForm()
|
||||
{
|
||||
return $this->importExportMakePartial('export_form');
|
||||
}
|
||||
|
||||
//
|
||||
// Exporting
|
||||
//
|
||||
|
||||
/**
|
||||
* Prepares the view data.
|
||||
* @return void
|
||||
*/
|
||||
public function prepareExportVars()
|
||||
{
|
||||
$this->vars['exportFormatFormWidget'] = $this->exportFormatFormWidget;
|
||||
$this->vars['exportOptionsFormWidget'] = $this->exportOptionsFormWidget;
|
||||
$this->vars['exportColumns'] = $this->getExportColumns();
|
||||
|
||||
// Make these variables available to widgets
|
||||
$this->controller->vars += $this->vars;
|
||||
}
|
||||
|
||||
public function exportRender()
|
||||
{
|
||||
return $this->importExportMakePartial('export');
|
||||
}
|
||||
|
||||
public function exportGetModel()
|
||||
{
|
||||
return $this->getModelForType('export');
|
||||
}
|
||||
|
||||
protected function getExportColumns()
|
||||
{
|
||||
if ($this->exportColumns !== null) {
|
||||
return $this->exportColumns;
|
||||
}
|
||||
$columnConfig = $this->getConfig('export[list]');
|
||||
return $this->exportColumns = $this->makeListColumns($columnConfig);
|
||||
}
|
||||
|
||||
protected function makeExportFormatFormWidget()
|
||||
{
|
||||
if (!$this->getConfig('export')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$widgetConfig = $this->makeConfig('~/modules/backend/behaviors/importexportcontroller/partials/fields_export.yaml');
|
||||
$widgetConfig->model = $this->exportGetModel();
|
||||
$widgetConfig->alias = 'exportUploadForm';
|
||||
|
||||
$widget = $this->makeWidget('Backend\Widgets\Form', $widgetConfig);
|
||||
|
||||
$widget->bindEvent('form.beforeRefresh', function($holder) {
|
||||
$holder->data = [];
|
||||
});
|
||||
|
||||
return $widget;
|
||||
}
|
||||
|
||||
protected function makeExportOptionsFormWidget()
|
||||
{
|
||||
$widget = $this->makeOptionsFormWidgetForType('export');
|
||||
|
||||
if (!$widget && $this->exportFormatFormWidget) {
|
||||
$stepSection = $this->exportFormatFormWidget->getField('step3_section');
|
||||
$stepSection->hidden = true;
|
||||
}
|
||||
|
||||
return $widget;
|
||||
}
|
||||
|
||||
protected function processExportColumnsFromPost()
|
||||
{
|
||||
$visibleColumns = post('visible_columns', []);
|
||||
$columns = post('export_columns', []);
|
||||
|
||||
foreach ($columns as $key => $columnName) {
|
||||
if (!isset($visibleColumns[$columnName])) {
|
||||
unset($columns[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$result = [];
|
||||
$definitions = $this->getExportColumns();
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$result[$column] = array_get($definitions, $column, '???');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
|
|
@ -327,6 +499,41 @@ class ImportExportController extends ControllerBehavior
|
|||
return $contents;
|
||||
}
|
||||
|
||||
protected function makeOptionsFormWidgetForType($type)
|
||||
{
|
||||
if (!$this->getConfig($type)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($fieldConfig = $this->getConfig($type.'[form]')) {
|
||||
$widgetConfig = $this->makeConfig($fieldConfig);
|
||||
$widgetConfig->model = $this->getModelForType($type);
|
||||
$widgetConfig->alias = $type.'OptionsForm';
|
||||
$widgetConfig->arrayName = ucfirst($type).'Options';
|
||||
|
||||
$widget = $this->makeWidget('Backend\Widgets\Form', $widgetConfig);
|
||||
return $widget;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getModelForType($type)
|
||||
{
|
||||
$cacheProperty = $type.'Model';
|
||||
|
||||
if ($this->{$cacheProperty} !== null) {
|
||||
return $this->{$cacheProperty};
|
||||
}
|
||||
|
||||
$modelClass = $this->getConfig($type.'[modelClass]');
|
||||
if (!$modelClass) {
|
||||
throw new ApplicationException('Please specify the modelClass property for '.$type);
|
||||
}
|
||||
|
||||
return $this->{$cacheProperty} = new $modelClass;
|
||||
}
|
||||
|
||||
protected function makeListColumns($config)
|
||||
{
|
||||
$config = $this->makeConfig($config);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
.export-behavior .export-columns {
|
||||
max-height: 400px;
|
||||
background: #f0f0f0;
|
||||
padding: 15px;
|
||||
padding-bottom: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Scripts for the Export controller behavior.
|
||||
*/
|
||||
+function ($) { "use strict";
|
||||
|
||||
var ExportBehavior = function() {
|
||||
|
||||
this.processExport = function () {
|
||||
var $form = $('#exportColumns').closest('form')
|
||||
|
||||
$form.request('onExport', {
|
||||
success: function(data) {
|
||||
$('#exportContainer').html(data.result)
|
||||
$(document).trigger('render')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$.oc.exportBehavior = new ExportBehavior;
|
||||
}(window.jQuery);
|
||||
|
|
@ -1,10 +1,34 @@
|
|||
/*
|
||||
* Scripts for the Import/Export controller behavior.
|
||||
* Scripts for the Import controller behavior.
|
||||
*/
|
||||
+function ($) { "use strict";
|
||||
|
||||
var ImportBehavior = function() {
|
||||
|
||||
this.processImport = function () {
|
||||
var $form = $('#importFileColumns').closest('form')
|
||||
|
||||
$form.request('onImport', {
|
||||
success: function(data) {
|
||||
$('#importContainer').html(data.result)
|
||||
$(document).trigger('render')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.loadFileColumnSample = function(el) {
|
||||
var $el = $(el),
|
||||
$column = $el.closest('[data-column-id]'),
|
||||
columnId = $column.data('column-id')
|
||||
|
||||
$el.popup({
|
||||
handler: 'onImportLoadColumnSampleForm',
|
||||
extraData: {
|
||||
file_column_id: columnId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.bindColumnSorting = function() {
|
||||
/*
|
||||
* Unbind existing
|
||||
|
|
@ -85,29 +109,6 @@
|
|||
$('#showIgnoredColumnsButton').addClass('disabled')
|
||||
}
|
||||
|
||||
this.loadFileColumnSample = function(el) {
|
||||
var $el = $(el),
|
||||
$column = $el.closest('[data-column-id]'),
|
||||
columnId = $column.data('column-id')
|
||||
|
||||
$el.popup({
|
||||
handler: 'onImportLoadColumnSampleForm',
|
||||
extraData: {
|
||||
file_column_id: columnId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.processImport = function () {
|
||||
var $form = $('#importFileColumns').closest('form')
|
||||
|
||||
$form.request('onImport', {
|
||||
success: function(data) {
|
||||
$('#importContainer').html(data.result)
|
||||
$(document).trigger('render')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
$.oc.importBehavior = new ImportBehavior;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
@import "../../../../assets/less/core/boot.less";
|
||||
|
||||
.export-behavior {
|
||||
|
||||
.export-columns {
|
||||
max-height: 400px;
|
||||
background: #f0f0f0;
|
||||
padding: 15px;
|
||||
padding-bottom: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<div class="export-behavior">
|
||||
|
||||
<?= $exportFormatFormWidget->render() ?>
|
||||
|
||||
<?php if ($exportOptionsFormWidget): ?>
|
||||
<?= $exportOptionsFormWidget->render() ?>
|
||||
<?php endif ?>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<div class="export-columns" id="exportColumns">
|
||||
<div class="control-simplelist with-checkboxes is-sortable" data-control="simplelist">
|
||||
<ul>
|
||||
<?php foreach ($exportColumns as $key => $column): ?>
|
||||
<li>
|
||||
<div class="checkbox custom-checkbox">
|
||||
<input
|
||||
type="hidden"
|
||||
name="export_columns[]"
|
||||
value="<?= $key ?>" />
|
||||
<input
|
||||
id="<?= $this->getId('exportCheckbox-'.$key) ?>"
|
||||
name="visible_columns[<?= $key ?>]"
|
||||
value="1"
|
||||
checked="checked"
|
||||
type="checkbox" />
|
||||
<label
|
||||
class="choice"
|
||||
for="<?= $this->getId('exportCheckbox-'.$key) ?>">
|
||||
<?= e(trans($column)) ?>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<div id="exportFormPopup">
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?= Form::open(['id' => 'exportForm']) ?>
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">Export progress</h4>
|
||||
</div>
|
||||
|
||||
<div id="exportContainer">
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="loading-indicator-container">
|
||||
<p> </p>
|
||||
<div class="loading-indicator transparent">
|
||||
<div>Processing</div>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<p> </p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= Form::close() ?>
|
||||
|
||||
<script>
|
||||
$('#exportFormPopup').on('popupComplete', function() {
|
||||
$.oc.exportBehavior.processExport()
|
||||
})
|
||||
</script>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
||||
<h4 class="modal-title">Export error</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-default"
|
||||
data-dismiss="popup">
|
||||
<?= e(trans('backend::lang.form.close')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
File export process has completed successfully!
|
||||
The browser should now redirect automatically to the file download.
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-success"
|
||||
data-dismiss="popup">
|
||||
<?= e(trans('backend::lang.form.complete')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<script> window.location = '<?= $fileUrl ?>' </script>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<div class="modal-body">
|
||||
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-default"
|
||||
data-dismiss="popup">
|
||||
<?= e(trans('backend::lang.form.close')) ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<?php endif ?>
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
<?= $importUploadFormWidget->render() ?>
|
||||
|
||||
<?= $importOptionsFormWidget->render() ?>
|
||||
<?php if ($importOptionsFormWidget): ?>
|
||||
<?= $importOptionsFormWidget->render() ?>
|
||||
<?php endif ?>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
# ===================================
|
||||
# Field Definitions
|
||||
# ===================================
|
||||
|
||||
fields:
|
||||
step1_section:
|
||||
label: 1. Export output format
|
||||
type: section
|
||||
|
||||
format_preset:
|
||||
label: File format
|
||||
type: dropdown
|
||||
default: standard
|
||||
options:
|
||||
standard: Standard format
|
||||
custom: Custom format
|
||||
span: left
|
||||
|
||||
format_delimiter:
|
||||
label: Delimiter character
|
||||
default: ','
|
||||
span: left
|
||||
trigger:
|
||||
action: show
|
||||
condition: value[custom]
|
||||
field: format_preset
|
||||
|
||||
format_enclosure:
|
||||
label: Enclosure character
|
||||
span: auto
|
||||
default: '"'
|
||||
trigger:
|
||||
action: show
|
||||
condition: value[custom]
|
||||
field: format_preset
|
||||
|
||||
format_escape:
|
||||
label: Escape character
|
||||
span: auto
|
||||
default: '\\'
|
||||
trigger:
|
||||
action: show
|
||||
condition: value[custom]
|
||||
field: format_preset
|
||||
|
||||
step2_section:
|
||||
label: 2. Select columns to export
|
||||
type: section
|
||||
|
||||
export_columns:
|
||||
label: Columns
|
||||
type: partial
|
||||
path: ~/modules/backend/behaviors/importexportcontroller/partials/_export_columns.htm
|
||||
span: left
|
||||
|
||||
step3_section:
|
||||
label: 3. Set export options
|
||||
type: section
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
<?php namespace Backend\Models;
|
||||
|
||||
use File;
|
||||
use Lang;
|
||||
use Model;
|
||||
use Response;
|
||||
use League\Csv\Writer as CsvWriter;
|
||||
use ApplicationException;
|
||||
use SplTempFileObject;
|
||||
|
||||
/**
|
||||
* Model used for exporting data
|
||||
*
|
||||
* @package october\backend
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*/
|
||||
abstract class ExportModel extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Called when data is being exported.
|
||||
* The return value should be an array in the format of:
|
||||
*
|
||||
* [
|
||||
* 'db_name1' => 'Some attribute value',
|
||||
* 'db_name2' => 'Another attribute value'
|
||||
* ],
|
||||
* [...]
|
||||
*
|
||||
*/
|
||||
abstract public function exportData($columns, $sessionKey = null);
|
||||
|
||||
/**
|
||||
* Export data based on column names and labels.
|
||||
* The $columns array should be in the format of:
|
||||
*
|
||||
* [
|
||||
* 'db_name1' => 'Column label',
|
||||
* 'db_name2' => 'Another label',
|
||||
* ...
|
||||
* ]
|
||||
*
|
||||
*/
|
||||
public function export($columns, $options)
|
||||
{
|
||||
$sessionKey = array_get($options, 'sessionKey');
|
||||
$data = $this->exportData(array_keys($columns), $sessionKey);
|
||||
return $this->processExportData($columns, $data, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a previously compiled export file.
|
||||
* @return void
|
||||
*/
|
||||
public function download($name, $outputName = null)
|
||||
{
|
||||
if (!preg_match('/^oc[0-9a-z]*$/i', $name)) {
|
||||
throw new ApplicationException('File not found');
|
||||
}
|
||||
|
||||
$csvPath = temp_path() . '/' . $name;
|
||||
if (!file_exists($csvPath)) {
|
||||
throw new ApplicationException('File not found');
|
||||
}
|
||||
|
||||
$headers = Response::download($csvPath, $outputName)->headers->all();
|
||||
$result = Response::make(File::get($csvPath), 200, $headers);
|
||||
|
||||
@unlink($csvPath);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a data collection to a CSV file.
|
||||
*/
|
||||
protected function processExportData($columns, $results, $options)
|
||||
{
|
||||
/*
|
||||
* Validate
|
||||
*/
|
||||
if (!$results) {
|
||||
throw new ApplicationException('There was no data supplied to export');
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse options
|
||||
*/
|
||||
$defaultOptions = [
|
||||
'useOutput' => false,
|
||||
'fileName' => 'export.csv',
|
||||
'delimiter' => null,
|
||||
'enclosure' => null,
|
||||
'escape' => null
|
||||
];
|
||||
|
||||
$options = array_merge($defaultOptions, $options);
|
||||
$columns = $this->exportExtendColumns($columns);
|
||||
|
||||
/*
|
||||
* Prepare CSV
|
||||
*/
|
||||
$csv = CsvWriter::createFromFileObject(new SplTempFileObject);
|
||||
|
||||
if ($options['delimiter'] !== null) {
|
||||
$csv->setDelimiter($options['delimiter']);
|
||||
}
|
||||
|
||||
if ($options['enclosure'] !== null) {
|
||||
$csv->setEnclosure($options['enclosure']);
|
||||
}
|
||||
|
||||
if ($options['escape'] !== null) {
|
||||
$csv->setEscape($options['escape']);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add headers
|
||||
*/
|
||||
$headers = $this->getColumnHeaders($columns);
|
||||
$csv->insertOne($headers);
|
||||
|
||||
/*
|
||||
* Add records
|
||||
*/
|
||||
foreach ($results as $result) {
|
||||
$data = $this->matchDataToColumns($result, $columns);
|
||||
$csv->insertOne($data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output
|
||||
*/
|
||||
if ($options['useOutput']) {
|
||||
$csv->output($options['fileName']);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save for download
|
||||
*/
|
||||
$csvName = uniqid('oc');
|
||||
$csvPath = temp_path().'/'.$csvName;
|
||||
$output = $csv->__toString();
|
||||
|
||||
File::put($csvPath, $output);
|
||||
|
||||
return $csvName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to override column definitions at export time.
|
||||
*/
|
||||
protected function exportExtendColumns($columns)
|
||||
{
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the headers from the column definitions.
|
||||
*/
|
||||
protected function getColumnHeaders($columns)
|
||||
{
|
||||
$headers = [];
|
||||
|
||||
foreach ($columns as $column => $label) {
|
||||
$headers[] = Lang::get($label);
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the correct order of the column data.
|
||||
*/
|
||||
protected function matchDataToColumns($data, $columns)
|
||||
{
|
||||
$results = [];
|
||||
|
||||
foreach ($columns as $column => $label) {
|
||||
$results[] = array_get($data, $column);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -26,6 +26,9 @@ abstract class ImportModel extends Model
|
|||
'import_file' => ['System\Models\File']
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array Import statistics store.
|
||||
*/
|
||||
protected $resultStats = [
|
||||
'updated' => 0,
|
||||
'created' => 0,
|
||||
|
|
@ -36,11 +39,33 @@ abstract class ImportModel extends Model
|
|||
|
||||
/**
|
||||
* Called when data is being imported.
|
||||
* The $results array should be in the format of:
|
||||
*
|
||||
* [
|
||||
* 'db_name1' => 'Some value',
|
||||
* 'db_name2' => 'Another value'
|
||||
* ],
|
||||
* [...]
|
||||
*
|
||||
*/
|
||||
abstract public function importData($results, $sessionKey = null);
|
||||
|
||||
public function importDataFromColumnMatch($matches, $sessionKey = null, $options = [])
|
||||
/**
|
||||
* Import data based on column names matching header indexes in the CSV.
|
||||
* The $matches array should be in the format of:
|
||||
*
|
||||
* [
|
||||
* 0 => [db_name1, db_name2],
|
||||
* 1 => [db_name3],
|
||||
* ...
|
||||
* ]
|
||||
*
|
||||
* The key (0, 1) is the column index in the CSV and the value
|
||||
* is another array of target database column names.
|
||||
*/
|
||||
public function import($matches, $options = [])
|
||||
{
|
||||
$sessionKey = array_get($options, 'sessionKey');
|
||||
$path = $this->getImportFilePath($sessionKey);
|
||||
$data = $this->processImportData($path, $matches, $options);
|
||||
return $this->importData($data, $sessionKey);
|
||||
|
|
@ -48,11 +73,12 @@ abstract class ImportModel extends Model
|
|||
|
||||
/**
|
||||
* Converts column index to database column map to an array containing
|
||||
* database column names and values pulled from the CSV file.
|
||||
* Eg:
|
||||
* 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],
|
||||
* [...]
|
||||
|
|
|
|||
Loading…
Reference in New Issue