Commit 35126eb6 authored by Simon Gadient's avatar Simon Gadient

[TASK] Initial commit with base functionality

refs KIME-4583
parents
<?php
namespace WE\SpreadsheetImport\Annotations;
/* *
* 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! *
* */
/**
* Defines the column mapping for a property
*
* @Annotation
* @Target({"PROPERTY"})
*/
final class Mapping {
/**
* @var string
*/
public $labelId = '';
/**
* @var boolean
*/
public $identifier = FALSE;
/**
* @var string
*/
public $setter;
}
<?php
namespace WE\SpreadsheetImport\Domain\Model;
/* *
* 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 Doctrine\ORM\Mapping as ORM;
/**
* @Flow\Entity
*/
class SpreadsheetImport {
/**
* @var string
* @Flow\Validate(type="NotEmpty")
*/
protected $context;
/**
* @ORM\OneToOne(cascade={"persist"})
* @var \TYPO3\Flow\Resource\Resource
*/
protected $file;
/**
* @var \DateTime
*/
protected $scheduleDate;
/**
* @var string
*/
protected $mapping = '';
/**
* @var boolean
*/
protected $inserting = FALSE;
/**
* @var boolean
*/
protected $updating = FALSE;
/**
* @var boolean
*/
protected $deleting = FALSE;
/**
* @var int
*/
protected $totalInserted = 0;
/**
* @var int
*/
protected $totalUpdated = 0;
/**
* @var int
*/
protected $totalDeleted = 0;
/**
* @var int
*/
protected $totalSkipped = 0;
/**
* SpreadsheetImport constructor.
*/
public function __construct() {
$this->scheduleDate = new \DateTime();
}
/**
* @return string
*/
public function getContext() {
return $this->context;
}
/**
* @param string $context
*/
public function setContext($context) {
$this->context = $context;
}
/**
* @return \TYPO3\Flow\Resource\Resource
*/
public function getFile() {
return $this->file;
}
/**
* @param \TYPO3\Flow\Resource\Resource $file
*/
public function setFile($file) {
$this->file = $file;
}
/**
* @return \DateTime
*/
public function getScheduleDate() {
return $this->scheduleDate;
}
/**
* @param \DateTime $scheduleDate
*/
public function setScheduleDate($scheduleDate) {
$this->scheduleDate = $scheduleDate;
}
/**
* @return array
*/
public function getMapping() {
return unserialize($this->mapping);
}
/**
* @param array $mapping
*/
public function setMapping($mapping) {
$this->mapping = serialize($mapping);
}
/**
* @return boolean
*/
public function isInserting() {
return $this->inserting;
}
/**
* @param boolean $inserting
*/
public function setInserting($inserting) {
$this->inserting = $inserting;
}
/**
* @return boolean
*/
public function isUpdating() {
return $this->updating;
}
/**
* @param boolean $updating
*/
public function setUpdating($updating) {
$this->updating = $updating;
}
/**
* @return boolean
*/
public function isDeleting() {
return $this->deleting;
}
/**
* @param boolean $deleting
*/
public function setDeleting($deleting) {
$this->deleting = $deleting;
}
/**
* @return int
*/
public function getTotalInserted() {
return $this->totalInserted;
}
/**
* @param int $totalInserted
*/
public function setTotalInserted($totalInserted) {
$this->totalInserted = $totalInserted;
}
/**
* @return int
*/
public function getTotalUpdated() {
return $this->totalUpdated;
}
/**
* @param int $totalUpdated
*/
public function setTotalUpdated($totalUpdated) {
$this->totalUpdated = $totalUpdated;
}
/**
* @return int
*/
public function getTotalDeleted() {
return $this->totalDeleted;
}
/**
* @param int $totalDeleted
*/
public function setTotalDeleted($totalDeleted) {
$this->totalDeleted = $totalDeleted;
}
/**
* @return int
*/
public function getTotalSkipped() {
return $this->totalSkipped;
}
/**
* @param int $totalSkipped
*/
public function setTotalSkipped($totalSkipped) {
$this->totalSkipped = $totalSkipped;
}
}
<?php
namespace WE\SpreadsheetImport\Domain\Model;
/* *
* 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! *
* */
interface SpreadsheetImportTargetInterface {
/**
* @param boolean $updated
*
* @return void
*/
public function setUpdated($updated);
/**
* @param \DateTime $lastUpdated
*
* @return void
*/
public function isUpdated($lastUpdated);
/**
* @return array
*/
public static function getAdditionalProperties();
}
<?php
namespace WE\SpreadsheetImport\Domain\Repository;
/* *
* 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\Persistence\Repository;
/**
* @Flow\Scope("singleton")
*/
class SpreadsheetImportRepository extends Repository {
}
<?php
namespace WE\SpreadsheetImport;
/* *
* 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 WE\SpreadsheetImport\Annotations\Mapping;
use WE\SpreadsheetImport\Domain\Model\SpreadsheetImport;
/**
* @Flow\Scope("singleton")
*/
class SpreadsheetImportService {
/**
* @var SpreadsheetImport
*/
protected $spreadsheetImport;
/**
* @var array
*/
protected $context;
/**
* @Flow\InjectConfiguration
* @var array
*/
protected $settings;
/**
* @Flow\Inject
* @var \TYPO3\Flow\Reflection\ReflectionService
*/
protected $reflectionService;
/**
* @Flow\Inject
* @var \TYPO3\Flow\Resource\ResourceManager
*/
protected $resourceManager;
/**
* @param \WE\SpreadsheetImport\Domain\Model\SpreadsheetImport $spreadsheetImport
*
* @return $this
*/
public function init(SpreadsheetImport $spreadsheetImport) {
$this->spreadsheetImport = $spreadsheetImport;
$this->context = $this->settings[$spreadsheetImport->getContext()];
return $this;
}
/**
* @return array
*/
public function getDomainMappingProperties() {
$domainMappingProperties = array();
$properties = $this->reflectionService->getPropertyNamesByAnnotation($this->context['domain'], Mapping::class);
foreach ($properties as $property) {
$domainMappingProperties[$property] = $this->reflectionService->getPropertyAnnotation($this->context['domain'], $property, Mapping::class);
}
return $domainMappingProperties;
}
/**
* @return array
*/
public function getSpreadsheetColumns() {
$columns = array();
$file = $this->spreadsheetImport->getFile()->createTemporaryLocalCopy();
$reader = \PHPExcel_IOFactory::load($file);
$sheet = $reader->getActiveSheet();
$highestColumn = $sheet->getHighestDataColumn();
$row = $sheet->getRowIterator(1, 1)->current();
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(FALSE);
/** @var \PHPExcel_Cell $cell */
foreach ($cellIterator as $cell) {
$columns[$cell->getColumn()] = $cell->getValue();
if ($cell->getColumn() === $highestColumn) {
break;
}
}
return $columns;
}
/**
* @param int $number
*
* @return object
*/
public function getObjectByRow($number) {
$domain = $this->context['domain'];
$newObject = new $domain;
// Plus one to skip the headings
$file = $this->spreadsheetImport->getFile()->createTemporaryLocalCopy();
$reader = \PHPExcel_IOFactory::load($file);
$row = $reader->getActiveSheet()->getRowIterator($number + 1, $number + 1)->current();
$this->setObjectPropertiesByRow($newObject, $row);
return $newObject;
}
/**
* @return array
*/
public function import() {
// TODO: This simply creates the objects for now without update or delete
$objects = array();
$domain = $this->context['domain'];
$file = $this->spreadsheetImport->getFile()->createTemporaryLocalCopy();
$reader = \PHPExcel_IOFactory::load($file);
/** @var \PHPExcel_Worksheet_Row $row */
foreach ($reader->getActiveSheet()->getRowIterator(2) as $row) {
$newObject = new $domain;
$this->setObjectPropertiesByRow($newObject, $row);
$objects[] = $newObject;
}
return $objects;
}
/**
* @param object $newObject
* @param \PHPExcel_Worksheet_Row $row
*/
private function setObjectPropertiesByRow($newObject, $row) {
// TODO: Cache $domainMappingProperties and $mappings
$domainMappingProperties = $this->getDomainMappingProperties();
$mappings = $this->spreadsheetImport->getMapping();
/** @var \PHPExcel_Cell $cell */
foreach ($row->getCellIterator() as $cell) {
$column = $cell->getColumn();
if (array_key_exists($column, $mappings)) {
$property = $mappings[$column];
/** @var Mapping $mapping */
$mapping = $domainMappingProperties[$property];
$setter = empty($mapping->setter) ? 'set' . ucfirst($property) : $mapping->setter;
$newObject->$setter($cell->getValue());
}
}
}
}
WE:
SpreadsheetImport:
swisscomGrb:
domain: WE\KIME\Domain\Model\User
Configuration:
userProfileType:
setter: convertUserProfileTypeBySysValue
value: 'swisscomGRB'
privacy:
value: 'private'
WE:
SpreadsheetImport:
testing:
domain: WE\SpreadsheetImport\Tests\Functional\Fixtures\ImportTarget
labelPackageKey: 'WE.SpreadsheetImport'
Configuration:
userProfileType:
setter: convertUserProfileTypeBySysValue
value: 'swisscomGRB'
privacy:
value: 'private'
<?php
namespace TYPO3\Flow\Persistence\Doctrine\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
/**
* Spreadsheet import domain
*/
class Version20161003124329 extends AbstractMigration
{
/**
* @return string
*/
public function getDescription() {
return '';
}
/**
* @param Schema $schema
* @return void
*/
public function up(Schema $schema)
{
// this up() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on "mysql".');
$this->addSql('CREATE TABLE we_spreadsheetimport_domain_model_spreadsheetimport (persistence_object_identifier VARCHAR(40) NOT NULL, file VARCHAR(40) DEFAULT NULL, context VARCHAR(255) NOT NULL, scheduledate DATETIME NOT NULL, mapping LONGTEXT NOT NULL, `inserting` TINYINT(1) NOT NULL, `updating` TINYINT(1) NOT NULL, `deleting` TINYINT(1) NOT NULL, totalinserted INT NOT NULL, totalupdated INT NOT NULL, totaldeleted INT NOT NULL, totalskipped INT NOT NULL, UNIQUE INDEX UNIQ_19518FA38C9F3610 (file), PRIMARY KEY(persistence_object_identifier)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
$this->addSql('ALTER TABLE we_spreadsheetimport_domain_model_spreadsheetimport ADD CONSTRAINT FK_19518FA38C9F3610 FOREIGN KEY (file) REFERENCES typo3_flow_resource_resource (persistence_object_identifier)');
}
/**
* @param Schema $schema
* @return void
*/
public function down(Schema $schema)
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on "mysql".');
$this->addSql('DROP TABLE we_spreadsheetimport_domain_model_spreadsheetimport');
}
}
<?php
namespace WE\SpreadsheetImport\Tests\Functional\Fixtures;
/* *
* 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 WE\SpreadsheetImport\Annotations as SpreadsheetImport;
use WE\SpreadsheetImport\Domain\Model\SpreadsheetImportTargetInterface;
/**
* @Flow\Entity
*/
class ImportTarget implements SpreadsheetImportTargetInterface {
/**
* @var string
* @SpreadsheetImport\Mapping(identifier=true, setter="setRawId")
*/
protected $id;
/**
* @var string
* @SpreadsheetImport\Mapping
*/
protected $name;
/**
* @return string
*/
public function getId() {
return $this->id;
}
/**
* @param string $id
*/
public function setId($id) {
$this->id = $id;
}
/**
* @param string $id
*/
public function setRawId($id) {
$this->id = sprintf("%05d", $id);
}
/**
* @return string
*/
public function getName() {
return $this->name;
}
/**
* @param string $name
*/
public function setName($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.
}
}
<?php
namespace WE\SpreadsheetImport\Tests\Functional;
/* *
* 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\Reflection\ReflectionService;
use TYPO3\Flow\Resource\Resource;
use TYPO3\Flow\Resource\ResourceManager;
use TYPO3\Flow\Tests\FunctionalTestCase;
use WE\SpreadsheetImport\Annotations\Mapping;
use WE\SpreadsheetImport\Domain\Model\SpreadsheetImport;
use WE\SpreadsheetImport\SpreadsheetImportService;
use WE\SpreadsheetImport\Tests\Functional\Fixtures\ImportTarget;
class SpreadsheetImportServiceTest extends FunctionalTestCase {
/**
* @var SpreadsheetImportService
*/
protected $spreadsheetImportService;
/**
* @var \TYPO3\Flow\Resource\ResourceManager
*/
protected $resourceManager;
/**
* @return void
*/
public function setUp() {
parent::setUp();
$this->spreadsheetImportService = $this->objectManager->get(SpreadsheetImportService::class);
$this->resourceManager = $this->objectManager->get(ResourceManager::class);
$reflectionService = $this->objectManager->get(ReflectionService::class);
$this->inject($this->spreadsheetImportService, 'reflectionService', $reflectionService);
$this->initializeSpreadsheetMock();
}
/**
* @return void
*/
public function tearDown() {
$persistenceManager = self::$bootstrap->getObjectManager()->get('TYPO3\Flow\Persistence\PersistenceManagerInterface');
if (is_callable(array($persistenceManager, 'tearDown'))) {
$persistenceManager->tearDown();
}
self::$bootstrap->getObjectManager()->forgetInstance('TYPO3\Flow\Persistence\PersistenceManagerInterface');
parent::tearDown();
}
private function initializeSpreadsheetMock() {
$spreadsheetImport = new SpreadsheetImport();
$spreadsheetImport->setContext('testing');
$resource = $this->resourceManager->importResource(__DIR__ . '/Fixtures/Resources/sample.xlsx');
$spreadsheetImport->setFile($resource);
$spreadsheetImport->setMapping(array('C' => 'id', 'A' => 'name'));
$this->spreadsheetImportService->init($spreadsheetImport);
}
/**
* @test
*/
public function getMappingPropertiesReturnsPropertiesWithMappingAnnotation() {
$properties = $this->spreadsheetImportService->getDomainMappingProperties();
$this->assertArrayHasKey('id', $properties);
$this->assertArrayHasKey('name', $properties);
/** @var Mapping $id */
$id = $properties['id'];
/** @var Mapping $name */
$name = $properties['name'];
$this->assertSame(TRUE, $id->identifier);
$this->assertSame(FALSE, $name->identifier);
}
/**
* @test
*/
public function getSpreadsheetColumnsReturnsColumnsWithHeadings() {
$columns = $this->spreadsheetImportService->getSpreadsheetColumns();
$this->assertArrayHasKey('A', $columns);
$this->assertArrayHasKey('B', $columns);
$this->assertArrayHasKey('C', $columns);
$this->assertContains('name', $columns);
$this->assertContains('lastname', $columns);
$this->assertContains('id', $columns);
}
/**
* @test
*/
public function getObjectByRowOneReturnsImportTargetWithSetProperties() {
/** @var ImportTarget $object */
$object = $this->spreadsheetImportService->getObjectByRow(1);
$this->assertEquals('00001', $object->getId());
$this->assertEquals('Hans', $object->getName());
}
}
{
"description": "A Flow package to import spreadsheet records into configurable domain objects",
"type": "typo3-flow-package",
"name": "we/spreadsheetimport",
"license": [
"LGPL-3.0",
"MIT"
],
"require": {
"typo3/flow": "*"
},
"autoload": {
"psr-0": {
"WE\\SpreadsheetImport": "Classes/"
}
}
}
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