Commit 0f755ee6 authored by Chhengleap Soem's avatar Chhengleap Soem

Merge branch 'KIME-4583' into 'master'

Refactoring and Documentation



See merge request !14
parents ce2edd20 9af7082e
...@@ -12,7 +12,7 @@ namespace WE\SpreadsheetImport\Annotations; ...@@ -12,7 +12,7 @@ namespace WE\SpreadsheetImport\Annotations;
* */ * */
/** /**
* Defines the column mapping for a property * Annotation to define the column mapping for a property
* *
* @Annotation * @Annotation
* @Target({"PROPERTY"}) * @Target({"PROPERTY"})
......
...@@ -46,12 +46,12 @@ class SpreadsheetImportCommandController extends CommandController { ...@@ -46,12 +46,12 @@ class SpreadsheetImportCommandController extends CommandController {
protected $settings; protected $settings;
/** /**
* Import one pending queued spreadsheet into Domain data, and it will import the next one if it is done * Import next queued spreadsheets into domain objects asynchronously.
*/ */
public function importCommand() { public function importCommand() {
$currentImportingCount = $this->spreadsheetImportRepository->countByImportingStatus(SpreadsheetImport::IMPORTING_STATUS_IN_PROGRESS); $currentImportingCount = $this->spreadsheetImportRepository->countByImportingStatus(SpreadsheetImport::IMPORTING_STATUS_IN_PROGRESS);
if ($currentImportingCount > 0) { if ($currentImportingCount > 0) {
$this->outputFormatted('There is a progressing importing spreadsheet.'); $this->outputFormatted('Previous spreadsheet import is still in progress.');
$this->quit(); $this->quit();
} }
/** @var SpreadsheetImport $spreadsheetImport */ /** @var SpreadsheetImport $spreadsheetImport */
...@@ -67,25 +67,25 @@ class SpreadsheetImportCommandController extends CommandController { ...@@ -67,25 +67,25 @@ class SpreadsheetImportCommandController extends CommandController {
try { try {
$this->spreadsheetImportService->import(); $this->spreadsheetImportService->import();
$spreadsheetImport->setImportingStatus(SpreadsheetImport::IMPORTING_STATUS_COMPLETED); $spreadsheetImport->setImportingStatus(SpreadsheetImport::IMPORTING_STATUS_COMPLETED);
$this->outputFormatted('Spreadsheet has been imported. (totalInserted: %d, totalUpdated: %d, totalDeleted: %d, totalSkipped: %d)', $this->outputFormatted('Spreadsheet has been imported. %d inserted, %d updated, %d deleted, %d skipped',
array($spreadsheetImport->getTotalInserted(), $spreadsheetImport->getTotalUpdated(), $spreadsheetImport->getTotalDeleted(), $spreadsheetImport->getTotalSkipped())); array($spreadsheetImport->getTotalInserted(), $spreadsheetImport->getTotalUpdated(), $spreadsheetImport->getTotalDeleted(), $spreadsheetImport->getTotalSkipped()));
} catch (Exception $e) { } catch (Exception $e) {
$spreadsheetImport->setImportingStatus(SpreadsheetImport::IMPORTING_STATUS_FAILED); $spreadsheetImport->setImportingStatus(SpreadsheetImport::IMPORTING_STATUS_FAILED);
$this->outputFormatted('Spreadsheet imported failed.'); $this->outputFormatted('Spreadsheet import failed.');
} }
$this->spreadsheetImportRepository->update($spreadsheetImport); $this->spreadsheetImportRepository->update($spreadsheetImport);
} else { } else {
$this->outputFormatted('There is no spreadsheet importing in queue.'); $this->outputFormatted('No spreadsheet import in queue.');
} }
} }
/** /**
* Cleanup previous spreadsheet imports by specific time (defined by settings) * Cleanup previous spreadsheet imports. Threashold defined in settings.
*/ */
public function cleanupCommand() { public function cleanupCommand() {
$cleanupImportFromPreviousDay = $this->settings['cleanupImportFromPreviousDay']; $cleanupImportsThreasholdDays = intval($this->settings['cleanupImportsThreasholdDays']);
$cleanupFromDate = new \DateTime(); $cleanupFromDate = new \DateTime();
$cleanupFromDate->sub(new \DateInterval('P' . $cleanupImportFromPreviousDay . 'D')); $cleanupFromDate->sub(new \DateInterval('P' . $cleanupImportsThreasholdDays . 'D'));
$oldSpreadsheetImports = $this->spreadsheetImportRepository->findPreviousImportsBySpecificDate($cleanupFromDate); $oldSpreadsheetImports = $this->spreadsheetImportRepository->findPreviousImportsBySpecificDate($cleanupFromDate);
if ($oldSpreadsheetImports->count() > 0) { if ($oldSpreadsheetImports->count() > 0) {
/** @var SpreadsheetImport $oldSpreadsheetImport */ /** @var SpreadsheetImport $oldSpreadsheetImport */
......
<?php
namespace WE\SpreadsheetImport\Controller;
/* *
* This script belongs to the Flow package "SpreadsheetImport". *
* *
* It is free software; you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License, either version 3 *
* of the License, or (at your option) any later version. *
* *
* The TYPO3 project - inspiring people to share! *
* */
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Mvc\Controller\ActionController;
use WE\SpreadsheetImport\Domain\Model\SpreadsheetImport;
/**
* Controller for default import. This controller might be overwritten for the import of different domains.
*/
class SpreadsheetImportController extends ActionController {
/**
* @var string
*/
protected $context = 'default';
/**
* @Flow\Inject
* @var \WE\SpreadsheetImport\Domain\Repository\SpreadsheetImportRepository
*/
protected $spreadsheetImportRepository;
/**
* @Flow\Inject
* @var \WE\SpreadsheetImport\SpreadsheetImportService
*/
protected $spreadsheetImportService;
/**
* @Flow\Inject
* @var \WE\SpreadsheetImport\FrontendMappingService
*/
protected $frontendMappingService;
/**
* Initialize create action
*/
protected function initializeCreateAction() {
$this->arguments['newSpreadsheetImport']->getPropertyMappingConfiguration()->forProperty('scheduleDate')
->setTypeConverterOption('TYPO3\Flow\Property\TypeConverter\DateTimeConverter', \TYPO3\Flow\Property\TypeConverter\DateTimeConverter::CONFIGURATION_DATE_FORMAT, 'd.m.Y');
}
/**
* New action with context set statically
*/
public function newAction() {
$arguments = $this->frontendMappingService->getContextArgumentsForRequest($this->context, $this->request);
$spreadsheetImports = $this->spreadsheetImportRepository->findByContextAndArguments($this->context, $arguments);
$this->view->assign('spreadsheetImports', $spreadsheetImports);
$this->view->assign('arguments', serialize($arguments));
$this->view->assign('context', $this->context);
}
/**
* @param \WE\SpreadsheetImport\Domain\Model\SpreadsheetImport $newSpreadsheetImport
*/
public function createAction(SpreadsheetImport $newSpreadsheetImport) {
$formArguments = $this->request->getArguments();
$this->setScheduleDateTime($newSpreadsheetImport, $formArguments['scheduleTime']);
$this->setImportAction($newSpreadsheetImport, (int)$formArguments['action']);
$this->spreadsheetImportService->init($newSpreadsheetImport);
$mappingProperties = $this->spreadsheetImportService->getAnnotationMappingProperties();
$mappings = $this->frontendMappingService->getSpreadsheetImportMapping($mappingProperties);
$newSpreadsheetImport->setMapping($mappings);
$this->spreadsheetImportRepository->add($newSpreadsheetImport);
$this->redirect('mapping', NULL, NULL, array('spreadsheetImport' => $newSpreadsheetImport));
}
/**
* @param \WE\SpreadsheetImport\Domain\Model\SpreadsheetImport $spreadsheetImport
*/
public function mappingAction(SpreadsheetImport $spreadsheetImport) {
$this->spreadsheetImportService->init($spreadsheetImport);
$spreadsheetColumns = $this->spreadsheetImportService->getSpreadsheetColumns();
$this->view->assign('spreadsheetColumns', $spreadsheetColumns);
$this->view->assign('domainMappingProperties', $spreadsheetImport->getMapping());
$this->view->assign('spreadsheetImport', $spreadsheetImport);
}
/**
* @param \WE\SpreadsheetImport\Domain\Model\SpreadsheetImport $spreadsheetImport
*/
public function mapAction(SpreadsheetImport $spreadsheetImport) {
if ($spreadsheetImport->getImportingStatus() === SpreadsheetImport::IMPORTING_STATUS_DRAFT) {
$this->spreadsheetImportService->init($spreadsheetImport);
$mappingProperties = $this->spreadsheetImportService->getAnnotationMappingProperties();
$requestArguments = $this->request->getArguments();
$mappings = $this->frontendMappingService->getSpreadsheetImportMapping($mappingProperties, $requestArguments);
$spreadsheetImport->setMapping($mappings);
$this->spreadsheetImportRepository->update($spreadsheetImport);
}
$this->redirect('preview', NULL, NULL, array('spreadsheetImport' => $spreadsheetImport));
}
/**
* @param \WE\SpreadsheetImport\Domain\Model\SpreadsheetImport $spreadsheetImport
* @param int $record
*/
public function previewAction(SpreadsheetImport $spreadsheetImport, $record = 1) {
$this->spreadsheetImportService->init($spreadsheetImport);
$preview = $this->frontendMappingService->getMappingPreview($spreadsheetImport, $record);
$total = $this->spreadsheetImportService->getTotalRecords();
$this->view->assign('preview', $preview['preview']);
$this->view->assign('record', $record);
$this->view->assign('previous', $record - 1);
$this->view->assign('next', $record + 1);
$this->view->assign('total', $total);
$this->view->assign('hasErrors', $preview['hasErrors']);
$this->view->assign('spreadsheetImport', $spreadsheetImport);
}
/**
* @param \WE\SpreadsheetImport\Domain\Model\SpreadsheetImport $spreadsheetImport
*/
public function confirmAction(SpreadsheetImport $spreadsheetImport) {
$arguments = $spreadsheetImport->getArguments();
if ($spreadsheetImport->getImportingStatus() === SpreadsheetImport::IMPORTING_STATUS_DRAFT) {
$spreadsheetImport->setImportingStatus(SpreadsheetImport::IMPORTING_STATUS_IN_QUEUE);
$this->spreadsheetImportRepository->update($spreadsheetImport);
}
$this->redirect('new', NULL, NULL, $arguments);
}
/**
* @param \WE\SpreadsheetImport\Domain\Model\SpreadsheetImport $spreadsheetImport
*/
public function cancelAction(SpreadsheetImport $spreadsheetImport) {
$arguments = $spreadsheetImport->getArguments();
if ($spreadsheetImport->getImportingStatus() === SpreadsheetImport::IMPORTING_STATUS_DRAFT) {
$this->spreadsheetImportRepository->remove($spreadsheetImport);
$this->persistenceManager->persistAll();
}
$this->redirect('new', NULL, NULL, $arguments);
}
/**
* @param \WE\SpreadsheetImport\Domain\Model\SpreadsheetImport $spreadsheetImport
*/
public function deleteAction(SpreadsheetImport $spreadsheetImport) {
$arguments = $spreadsheetImport->getArguments();
if ($spreadsheetImport->getImportingStatus() <= SpreadsheetImport::IMPORTING_STATUS_IN_QUEUE) {
$this->spreadsheetImportRepository->remove($spreadsheetImport);
}
$this->redirect('new', NULL, NULL, $arguments);
}
/**
* @param SpreadsheetImport $spreadsheetImport
* @param $time
*/
private function setScheduleDateTime(SpreadsheetImport $spreadsheetImport, $time) {
$date = $spreadsheetImport->getScheduleDate();
$times = explode(':', $time);
$hour = isset($times[0]) ? $times[0] : 0;
$minute = isset($times[1]) ? $times[1] : 0;
$date->setTime($hour, $minute);
$spreadsheetImport->setScheduleDate($date);
}
/**
* @param \WE\SpreadsheetImport\Domain\Model\SpreadsheetImport $spreadsheetImport
* @param int $action
*/
private function setImportAction(SpreadsheetImport $spreadsheetImport, $action = 1) {
if ($action >= 1) {
$spreadsheetImport->setInserting(TRUE);
}
if ($action >= 2) {
$spreadsheetImport->setUpdating(TRUE);
}
if ($action >= 3) {
$spreadsheetImport->setDeleting(TRUE);
}
}
}
<?php <?php
namespace WE\SpreadsheetImport\Domain\Model; namespace WE\SpreadsheetImport\Exception;
/* * /* *
* This script belongs to the Flow package "SpreadsheetImport". * * This script belongs to the Flow package "SpreadsheetImport". *
...@@ -11,25 +11,8 @@ namespace WE\SpreadsheetImport\Domain\Model; ...@@ -11,25 +11,8 @@ namespace WE\SpreadsheetImport\Domain\Model;
* The TYPO3 project - inspiring people to share! * * The TYPO3 project - inspiring people to share! *
* */ * */
interface SpreadsheetImportTargetInterface { /**
* Generic SpreadsheetImport Exception
/** */
* @param boolean $updated class Exception extends \TYPO3\Flow\Exception {
*
* @return void
*/
public function setUpdated($updated);
/**
* @param \DateTime $lastUpdated
*
* @return void
*/
public function isUpdated($lastUpdated);
/**
* @return array
*/
public static function getAdditionalProperties();
} }
...@@ -15,6 +15,7 @@ use TYPO3\Flow\Annotations as Flow; ...@@ -15,6 +15,7 @@ use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Mvc\ActionRequest; use TYPO3\Flow\Mvc\ActionRequest;
use WE\SpreadsheetImport\Annotations\Mapping; use WE\SpreadsheetImport\Annotations\Mapping;
use WE\SpreadsheetImport\Domain\Model\SpreadsheetImport; use WE\SpreadsheetImport\Domain\Model\SpreadsheetImport;
use WE\SpreadsheetImport\Exception\Exception;
/** /**
* Service class of basic FE mapping functionality for simple usage on separate implementations. * Service class of basic FE mapping functionality for simple usage on separate implementations.
...@@ -57,10 +58,14 @@ class FrontendMappingService { ...@@ -57,10 +58,14 @@ class FrontendMappingService {
* @param string $context * @param string $context
* @param \TYPO3\Flow\Mvc\ActionRequest $request * @param \TYPO3\Flow\Mvc\ActionRequest $request
* *
* @throws \WE\SpreadsheetImport\Exception\Exception
* @return array * @return array
*/ */
public function getContextArgumentsForRequest($context, ActionRequest $request) { public function getContextArgumentsForRequest($context, ActionRequest $request) {
$arguments = array(); $arguments = array();
if (! isset($this->settings[$context]) || ! isset($this->settings[$context]['arguments'])) {
throw new Exception('Context with arguments needs to be configured in the Settings', 1478069710);
}
$contextArguments = $this->settings[$context]['arguments']; $contextArguments = $this->settings[$context]['arguments'];
if (is_array($contextArguments)) { if (is_array($contextArguments)) {
foreach ($contextArguments as $contextArgument) { foreach ($contextArguments as $contextArgument) {
...@@ -101,13 +106,18 @@ class FrontendMappingService { ...@@ -101,13 +106,18 @@ class FrontendMappingService {
/** /**
* @param \WE\SpreadsheetImport\Domain\Model\SpreadsheetImport $spreadsheetImport * @param \WE\SpreadsheetImport\Domain\Model\SpreadsheetImport $spreadsheetImport
* @param $record * @param int $record
* *
* @throws \WE\SpreadsheetImport\Exception\Exception
* @return array * @return array
*/ */
public function getMappingPreview(SpreadsheetImport $spreadsheetImport, $record) { public function getMappingPreview(SpreadsheetImport $spreadsheetImport, $record) {
$mapping = $spreadsheetImport->getMapping(); $mapping = $spreadsheetImport->getMapping();
$domain = $this->settings[$spreadsheetImport->getContext()]['domain']; $context = $spreadsheetImport->getContext();
if (! isset($this->settings[$context]) || ! isset($this->settings[$context]['arguments'])) {
throw new Exception('Context with arguments needs to be configured in the Settings', 1478069743);
}
$domain = $this->settings[$context]['domain'];
$record = max($record, 1); $record = max($record, 1);
$previewObject = $this->spreadsheetImportService->getObjectByRow($record); $previewObject = $this->spreadsheetImportService->getObjectByRow($record);
$preview = array(); $preview = array();
......
...@@ -137,8 +137,8 @@ class SpreadsheetImportService { ...@@ -137,8 +137,8 @@ class SpreadsheetImportService {
public function getObjectByRow($number) { public function getObjectByRow($number) {
$domain = $this->domain; $domain = $this->domain;
$newObject = new $domain; $newObject = new $domain;
// Plus one to skip the headings
$sheet = $this->getFileActiveSheet(); $sheet = $this->getFileActiveSheet();
// Plus one to skip the headings
$row = $sheet->getRowIterator($number + 1, $number + 1)->current(); $row = $sheet->getRowIterator($number + 1, $number + 1)->current();
$this->setObjectPropertiesByRow($newObject, $row); $this->setObjectPropertiesByRow($newObject, $row);
return $newObject; return $newObject;
...@@ -151,74 +151,62 @@ class SpreadsheetImportService { ...@@ -151,74 +151,62 @@ class SpreadsheetImportService {
$totalInserted = 0; $totalInserted = 0;
$totalUpdated = 0; $totalUpdated = 0;
$totalDeleted = 0; $totalDeleted = 0;
$totalSkipped = 0; $processedObjectIds = array();
$objectIds = array();
$domain = $this->domain;
$objectRepository = $this->getDomainRepository(); $objectRepository = $this->getDomainRepository();
$objectValidator = $this->validatorResolver->getBaseValidatorConjunction($domain); $objectValidator = $this->validatorResolver->getBaseValidatorConjunction($this->domain);
$identifierProperties = $this->getDomainMappingIdentifierProperties(); $identifierProperties = $this->getDomainMappingIdentifierProperties();
$sheet = $this->getFileActiveSheet(); $sheet = $this->getFileActiveSheet();
$numberOfRecordsToPersist = $this->settings['numberOfRecordsToPersist']; $persistRecordsChunkSize = intval($this->settings['persistRecordsChunkSize']);
$i = 0; $totalCount = 0;
/** @var \PHPExcel_Worksheet_Row $row */ /** @var \PHPExcel_Worksheet_Row $row */
foreach ($sheet->getRowIterator(2) as $row) { foreach ($sheet->getRowIterator(2) as $row) {
$totalCount++;
$object = $this->findObjectByIdentifierPropertiesPerRow($identifierProperties, $row); $object = $this->findObjectByIdentifierPropertiesPerRow($identifierProperties, $row);
if (is_object($object)) { if (is_object($object)) {
$objectIds[] = $this->persistenceManager->getIdentifierByObject($object); $processedObjectIds[] = $this->persistenceManager->getIdentifierByObject($object);
if ($this->spreadsheetImport->isUpdating()) { if ($this->spreadsheetImport->isUpdating()) {
$this->setObjectPropertiesByRow($object, $row); $this->setObjectPropertiesByRow($object, $row);
$validationResult = $objectValidator->validate($object); $validationResult = $objectValidator->validate($object);
if ($validationResult->hasErrors()) { if ($validationResult->hasErrors()) {
$totalSkipped++;
continue; continue;
} }
$objectRepository->update($object); $objectRepository->update($object);
$totalUpdated++; $totalUpdated++;
$i++;
} else { } else {
$totalSkipped++;
continue; continue;
} }
} elseif ($this->spreadsheetImport->isInserting()) { } elseif ($this->spreadsheetImport->isInserting()) {
$newObject = new $domain; $newObject = new $this->domain;
$this->setObjectPropertiesByRow($newObject, $row); $this->setObjectPropertiesByRow($newObject, $row);
$validationResult = $objectValidator->validate($newObject); $validationResult = $objectValidator->validate($newObject);
if ($validationResult->hasErrors()) { if ($validationResult->hasErrors()) {
$totalSkipped++;
continue; continue;
} }
$objectRepository->add($newObject); $objectRepository->add($newObject);
$objectIds[] = $this->persistenceManager->getIdentifierByObject($newObject); $processedObjectIds[] = $this->persistenceManager->getIdentifierByObject($newObject);
$totalInserted++; $totalInserted++;
$i++;
} else { } else {
$totalSkipped++;
continue; continue;
} }
if ($i >= $numberOfRecordsToPersist) { if ($totalCount % $persistRecordsChunkSize === 0) {
$this->persistenceManager->persistAll(); $this->persistenceManager->persistAll();
$i = 0;
} }
} }
$deleteCount = 0;
// remove objects which are not exist on the spreadsheet
if ($this->spreadsheetImport->isDeleting()) { if ($this->spreadsheetImport->isDeleting()) {
$notExistingObjects = $this->findObjectsByExcludedIds($objectIds); $notExistingObjects = $this->findObjectsByExcludedIds($processedObjectIds);
foreach ($notExistingObjects as $object) { foreach ($notExistingObjects as $object) {
$objectRepository->remove($object); $objectRepository->remove($object);
$totalDeleted++; if (++$deleteCount % $persistRecordsChunkSize === 0) {
$i++;
if ($i >= $numberOfRecordsToPersist) {
$this->persistenceManager->persistAll(); $this->persistenceManager->persistAll();
$i = 0;
} }
} }
} }
$this->persistenceManager->persistAll();
$this->spreadsheetImport->setTotalInserted($totalInserted); $this->spreadsheetImport->setTotalInserted($totalInserted);
$this->spreadsheetImport->setTotalUpdated($totalUpdated); $this->spreadsheetImport->setTotalUpdated($totalUpdated);
$this->spreadsheetImport->setTotalSkipped($totalCount - $totalInserted - $totalUpdated);
$this->spreadsheetImport->setTotalDeleted($totalDeleted); $this->spreadsheetImport->setTotalDeleted($totalDeleted);
$this->spreadsheetImport->setTotalSkipped($totalSkipped);
} }
/** /**
......
WE: WE:
SpreadsheetImport: SpreadsheetImport:
cleanupImportFromPreviousDay: 5 cleanupImportsThreasholdDays: 365
numberOfRecordsToPersist: 100 persistRecordsChunkSize: 100
swisscomGrb:
domain: WE\KIME\Domain\Model\User
Configuration:
userProfileType:
setter: convertUserProfileTypeBySysValue
value: 'swisscomGRB'
privacy:
value: 'private'
WE:
SpreadsheetImport:
cleanupImportsThreasholdDays: 365
persistRecordsChunkSize: 100
default:
domain: WE\Sample\Domain\Model\User
arguments:
- { name: category, domain: 'WE\Sample\Domain\Model\UserCategory', identifier: TRUE }
- { name: comment, static: 'Sample import' }
A Flow package to import spreadsheet records into configurable domain objects.
## Domain Model Configuration
### Settings
The package supports the import of different domain models. Each one needs to be configured in the setting files. A specific configuration is also referred to as 'Context'.
Minimum configuration example 'default' context:
WE:
SpreadsheetImport:
default:
domain: WE\Sample\Domain\Model\User
arguments: ~
### Mapping by Annotations
The domain model properties to be imported are specified by the `Mapping` annotation and can then be mapped to a column in the spreadsheet.
A simple property is specified the following way:
/**
* @var string
* @SpreadsheetImport\Mapping
*/
$firstName
`Mapping` supports properties to specify further configurations such as modified getters/setters, label, and the definition for identifiers. See the `WE\SpreadsheetImport\Annotations\Mapping` class for your reference.
### Argument Values
Besides the values that are imported from the spreadsheet, fix values are specified by parameter or statically in the settings. Example:
arguments:
- { name: category, domain: 'WE\Sample\Domain\Model\UserCategory', identifier: TRUE }
- { name: comment, static: 'Sample import' }
The argument 'category' expects a `UserCategory` object passed as parameter. It will be set to the object by `setCategory(..)`. Further, this value is used as identifier in the same way as the identifier property in the Mapping annotation.
The argument 'comment' has a static value and will simply call the `UserCategory::setComment('Sample import')`.
## Usage
### Technical
Per import, a specific `\WE\SpreadsheetImport\Domain\Model\SpreadsheetImport` object needs to be created, which then can be processed by the `SpreadsheetImportService::import()` function.
The object contains the column mapping between domain model and spreadsheet columns.
How the `SpreadsheetImport` object is created and progressed by the import function my vary per implementation and can easily be modified. The process implemented within this package works as a sample scenario but can be used out of the box with the simple configuration documented above.
### Sample Implementation
1. Call the `newAction` of the `SpreadsheetImportController` to create new `SpreadsheetImport` object.
2. On the next step of the dialog, the mapping between the configured domain model mapping properties and the spreadsheet columns needs to be done.
3. An object mapping preview shows the applied mapping and has to be confirmed.
4. After confirmation, the import is scheduled to import.
4. The function `./flow spreadsheetimport:import` has to be called to process the import.
To use the sample implementation, the controller might be extended and the `context` property overwritten.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Spreadsheet Import</title>
</head>
<body>
<f:render section="Content" />
</body>
</html>
<f:if condition="{spreadsheetImports}">
<h2><f:translate id="label.spreadsheet_import.list" /></h2>
<table>
<thead>
<tr>
<th><f:translate id="label.spreadsheet_import.schedule" /></th>
<th><f:translate id="label.spreadsheet_import.importingStatus" /></th>
<th><f:translate id="label.spreadsheet_import.file" /></th>
<th><f:translate id="label.spreadsheet_import.inserting" /></th>
<th><f:translate id="label.spreadsheet_import.updating" /></th>
<th><f:translate id="label.spreadsheet_import.deleting" /></th>
<th align="right"><f:translate id="label.spreadsheet_import.totalInserted" /></th>
<th align="right"><f:translate id="label.spreadsheet_import.totalUpdated" /></th>
<th align="right"><f:translate id="label.spreadsheet_import.totalDeleted" /></th>
<th align="right"><f:translate id="label.spreadsheet_import.totalSkipped" /></th>
<th></th>
</tr>
</thead>
<f:for each="{spreadsheetImports}" as="spreadsheetImport">
<tr>
<td><f:format.date format="d.m.Y H:i">{spreadsheetImport.scheduleDate}</f:format.date></td>
<td><f:render section="renderStatus" arguments="{status: spreadsheetImport.importingStatus}" /></td>
<td><a href="{f:uri.resource(resource: spreadsheetImport.file)}" title="{spreadsheetImport.file.filename}">{spreadsheetImport.file.filename}</a></td>
<td><f:if condition="{spreadsheetImport.inserting}">&#10003;</f:if></td>
<td><f:if condition="{spreadsheetImport.updating}">&#10003;</f:if></td>
<td><f:if condition="{spreadsheetImport.deleting}">&#10003;</f:if></td>
<td align="right">{spreadsheetImport.totalInserted}</td>
<td align="right">{spreadsheetImport.totalUpdated}</td>
<td align="right">{spreadsheetImport.totalDeleted}</td>
<td align="right">{spreadsheetImport.totalSkipped}</td>
<td>
<span class="action-icons pull-right">
<f:link.action action="mapping" arguments="{spreadsheetImport: spreadsheetImport}" title="{f:translate(id: 'label.spreadsheet_import.mapping')}">
<f:translate id="label.spreadsheet_import.action.mapping" />
</f:link.action>
<f:if condition="{spreadsheetImport.importingStatus} <= 1">
<f:form action="delete" arguments="{spreadsheetImport: spreadsheetImport}">
<button type="submit"><f:translate id="label.spreadsheet_import.action.delete" /></button>
</f:form>
</f:if>
</span>
</td>
</tr>
</f:for>
</table>
</f:if>
<f:section name="renderStatus">
<f:switch expression="{status}">
<f:case value="0">
<span class="label status-label status-draft">
<f:translate id="label.spreadsheet_import.importingStatus.draft" />
</span>
</f:case>
<f:case value="1">
<span class="label status-label status-queued">
<f:translate id="label.spreadsheet_import.importingStatus.inQueue" />
</span>
</f:case>
<f:case value="2">
<span class="label status-label status-progressing">
<f:translate id="label.spreadsheet_import.importingStatus.inProgress" />
</span>
</f:case>
<f:case value="3">
<span class="label status-label status-complete">
<f:translate id="label.spreadsheet_import.importingStatus.completed" />
</span>
</f:case>
<f:case value="4">
<span class="label status-label status-failed">
<f:translate id="label.spreadsheet_import.importingStatus.failed" />
</span>
</f:case>
</f:switch>
</f:section>
<f:layout name="Default" />
<f:section name="Content">
<h1><f:translate id="label.spreadsheet_import.mapping" /></h1>
<f:form action="map">
<f:form.hidden name="spreadsheetImport" value="{spreadsheetImport}"/>
<f:form.hidden name="event" value="{event}" />
<f:for each="{domainMappingProperties}" key="property" as="columnMapping">
<div>
<label for="{property}">
<f:if condition="{columnMapping.mapping.labelId}">
<f:then><f:translate id="{columnMapping.mapping.labelId}" /></f:then>
<f:else>{property}</f:else>
</f:if>
<f:if condition="{columnMapping.mapping.identifier}">
<span class="require"> * </span>
</f:if>
</label>
<div>
<f:if condition="{spreadsheetImport.importingStatus} == 0">
<f:then>
<f:if condition="{columnMapping.mapping.identifier}">
<f:then>
<f:form.select name="{property}" options="{spreadsheetColumns}" prependOptionLabel="{f:translate(id: 'label.please_select')}" value="{columnMapping.column}" additionalAttributes="{required: 1}" />
</f:then>
<f:else>
<f:form.select name="{property}" options="{spreadsheetColumns}" prependOptionLabel="{f:translate(id: 'label.please_select')}" value="{columnMapping.column}" />
</f:else>
</f:if>
</f:then>
<f:else>
<f:form.select name="{property}" options="{spreadsheetColumns}" prependOptionLabel="{f:translate(id: 'label.please_select')}" value="{columnMapping.column}" additionalAttributes="{disabled: 1}" />
</f:else>
</f:if>
</div>
</div>
</f:for>
<div>
<f:form.submit value="<f:translate id='label.spreadsheet_import.action.next'/>"/>
<f:link.action action="cancel" arguments="{spreadsheetImport: spreadsheetImport}"> <f:translate id="label.spreadsheet_import.action.cancel" /></f:link.action>
</div>
</f:form>
</f:section>
<f:layout name="Default" />
<f:section name="Content">
<h1><f:translate id="label.spreadsheet_import.new" /></h1>
<f:form action="create" objectName="newSpreadsheetImport" enctype="multipart/form-data">
<f:form.hidden property="context" value="{context}" />
<f:form.hidden property="arguments" value="{arguments}" />
<div>
<label for="file"><f:translate id="label.spreadsheet_import.file" /> <span class="require"> * </span></label>
<f:form.upload property="file" additionalAttributes="{accept: '.xlsx, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', required: 1}" />
</div>
<div>
<label for="schedule"><f:translate id="label.spreadsheet_import.schedule" /><span class="require"> * </span></label>
<f:form.textfield name="schedule" id="schedule" property="scheduleDate" required="1" placeholder="dd.mm.yyyy" value="{f:format.date(format : 'd.m.Y', date : 'NOW')}"/>
</div>
<div>
<label for="scheduleTime"><f:translate id="label.spreadsheet_import.schedule_time" /><span class="require"> * </span></label>
<f:form.textfield id="scheduleTime" name="scheduleTime" value="00:00" placeholder="hh:mm" required="1" />
</div>
<div>
<label><f:translate id="label.spreadsheet_import.new.import_actions" /></label>
<div>
<f:form.radio name="action" value="1" checked="1" id="insert" /> <label for="insert"> <f:translate id="label.spreadsheet_import.new.import_actions_inserting" /></label><br>
<f:form.radio name="action" value="2" id="insert-update" /> <label for="insert-update"> <f:translate id="label.spreadsheet_import.new.import_actions_updating" /></label><br>
<f:form.radio name="action" value="3" id="insert-update-delete" /> <label for="insert-update-delete"> <f:translate id="label.spreadsheet_import.new.import_actions_deleting" /></label>
</div>
</div>
<div>
<f:form.submit value="<f:translate id='label.spreadsheet_import.action.next'/>" />
</div>
</f:form>
<f:render partial="SpreadsheetImport/List" arguments="{_all}" />
</f:section>
<f:layout name="Default" />
<f:section name="Content">
<h1><f:translate id="label.spreadsheet_import.preview" /></h1>
<f:if condition="{hasErrors}">
<div><f:translate id="label.spreadsheet_import.preview.invalid_record" /></div>
</f:if>
<div>
<div>
<f:if condition="{record} > 1">
<f:link.action action="preview" arguments="{record: previous, spreadsheetImport: spreadsheetImport}">&lt;</f:link.action>
</f:if>
<f:translate id="label.spreadsheet_import.preview.record" /> {record}
<f:if condition="{record} < {total}">
<f:link.action action="preview" arguments="{record: next, spreadsheetImport: spreadsheetImport}">&gt;</f:link.action>
</f:if>
</div>
</div>
<f:form action="confirm">
<f:form.hidden name="spreadsheetImport" value="{spreadsheetImport}"/>
<f:for each="{preview}" key="property" as="previewMapping">
<div>
<label>
<f:if condition="{previewMapping.mapping.labelId}">
<f:then><f:translate id="{previewMapping.mapping.labelId}" />:</f:then>
<f:else>{property}:</f:else>
</f:if>
</label>
<div class="{f:if(condition: previewMapping.error, then: 'error-text')}">{previewMapping.value}</div>
</div>
</f:for>
<div>
<f:form.submit value="<f:translate id='label.spreadsheet_import.action.create'/>" />
<f:link.action action="cancel" arguments="{spreadsheetImport: spreadsheetImport}"> <f:translate id="label.spreadsheet_import.action.cancel" /></f:link.action>
</div>
</f:form>
</f:section>
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file original="" source-language="de" datatype="plaintext">
<body>
<trans-unit id="label.spreadsheet_import.action.next">
<source>Weiter</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.action.cancel">
<source>Abbrechen</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.action.create">
<source>Erstellen</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.action.mapping">
<source>Ansicht</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.action.delete">
<source>Löschen</source>
</trans-unit>
<!-- Views -->
<trans-unit id="label.spreadsheet_import.new">
<source>Neuer Spreadsheet Import</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.new.import_actions">
<source>Prozess</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.new.import_actions_inserting">
<source>Neue Datensätze erstellen</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.new.import_actions_updating">
<source>Neue Datensätze erstellen und existierende aktualisieren</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.new.import_actions_deleting">
<source>Neue Datensätze erstellen, existierende aktualisieren und nicht existierende löschen</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.mapping">
<source>Spalten Zuordnung</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.preview">
<source>Import Vorschau</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.preview.invalid_record">
<source>Ungültige Daten. Dieser Record wird nicht übersprungen.</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.preview.record">
<source>Zeile</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.list">
<source>Importe</source>
</trans-unit>
<!-- Status -->
<trans-unit id="label.spreadsheet_import.importingStatus">
<source>Status</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.importingStatus.draft">
<source>Entwurf</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.importingStatus.inQueue">
<source>Geplant</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.importingStatus.inProgress">
<source>In Bearbeitung</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.importingStatus.completed">
<source>Abgeschlossen</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.importingStatus.failed">
<source>Fehlgeschlagen</source>
</trans-unit>
<!-- SpreadsheetImport Model -->
<trans-unit id="label.spreadsheet_import.file">
<source>Datei</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.schedule">
<source>Ausführungs Datum</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.schedule_time">
<source>Ausführungs Zeit</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.inserting">
<source>Erstellen</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.updating">
<source>Aktualisieren</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.deleting">
<source>Löschen</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.totalInserted">
<source>Total Erstellt</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.totalUpdated">
<source>Total Aktualisiert</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.totalDeleted">
<source>Total Gelöscht</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.totalSkipped">
<source>Total Übersprungen</source>
</trans-unit>
</body>
</file>
</xliff>
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file original="" source-language="en" datatype="plaintext">
<body>
<trans-unit id="label.spreadsheet_import.action.next">
<source>Next</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.action.cancel">
<source>Cancel</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.action.create">
<source>Create</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.action.mapping">
<source>View</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.action.delete">
<source>Delete</source>
</trans-unit>
<!-- Views -->
<trans-unit id="label.spreadsheet_import.new">
<source>New Spreadsheet Import</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.new.import_actions">
<source>Actions</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.new.import_actions_inserting">
<source>Insert new records</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.new.import_actions_updating">
<source>Insert new and update existing records</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.new.import_actions_deleting">
<source>Insert new, update existing, and delete not existing records</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.mapping">
<source>Column Mapping</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.preview">
<source>Import Preview</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.preview.invalid_record">
<source>Invalid data. This record will be skipped.</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.preview.record">
<source>Record</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.list">
<source>Imports</source>
</trans-unit>
<!-- Status -->
<trans-unit id="label.spreadsheet_import.importingStatus">
<source>Status</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.importingStatus.draft">
<source>Draft</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.importingStatus.inQueue">
<source>In Queue</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.importingStatus.inProgress">
<source>In Progress</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.importingStatus.completed">
<source>Completed</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.importingStatus.failed">
<source>Failed</source>
</trans-unit>
<!-- SpreadsheetImport Model -->
<trans-unit id="label.spreadsheet_import.file">
<source>File</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.schedule">
<source>Schedule Date</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.schedule_time">
<source>Schedule Time</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.inserting">
<source>Insert</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.updating">
<source>Update</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.deleting">
<source>Delete</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.totalInserted">
<source>Total Inserted</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.totalUpdated">
<source>Total Updated</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.totalDeleted">
<source>Total Deleted</source>
</trans-unit>
<trans-unit id="label.spreadsheet_import.totalSkipped">
<source>Total Skipped</source>
</trans-unit>
</body>
</file>
</xliff>
...@@ -18,7 +18,7 @@ use WE\SpreadsheetImport\Domain\Model\SpreadsheetImportTargetInterface; ...@@ -18,7 +18,7 @@ use WE\SpreadsheetImport\Domain\Model\SpreadsheetImportTargetInterface;
/** /**
* @Flow\Entity * @Flow\Entity
*/ */
class ImportTarget implements SpreadsheetImportTargetInterface { class ImportTarget {
/** /**
* @var string * @var string
...@@ -66,16 +66,4 @@ class ImportTarget implements SpreadsheetImportTargetInterface { ...@@ -66,16 +66,4 @@ class ImportTarget implements SpreadsheetImportTargetInterface {
public function setName($name) { public function setName($name) {
$this->name = $name; $this->name = $name;
} }
public function setUpdated($updated) {
// TODO: Implement setUpdated() method.
}
public function isUpdated($lastUpdated) {
// TODO: Implement isUpdated() method.
}
public static function getAdditionalProperties() {
// TODO: Implement getAdditionalProperties() method.
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment