Commit ec1eae53 authored by Chivy Lim's avatar Chivy Lim
Browse files

Merge branch 'KIME-4583' into 'master'

Refactoring and argument identifier



See merge request !7
parents 8185499e 5e8c8d86
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -54,7 +54,7 @@ class SpreadsheetImportCommandController extends CommandController {
			$this->quit();
			$this->quit();
		}
		}
		/** @var SpreadsheetImport $spreadsheetImport */
		/** @var SpreadsheetImport $spreadsheetImport */
		$spreadsheetImport = $this->spreadsheetImportRepository->findPreviousOneInQueue();
		$spreadsheetImport = $this->spreadsheetImportRepository->findNextInQueue();
		if ($spreadsheetImport instanceof SpreadsheetImport) {
		if ($spreadsheetImport instanceof SpreadsheetImport) {
			// mark importing status as "Progressing" before continuing the importing
			// mark importing status as "Progressing" before continuing the importing
			$spreadsheetImport->setImportingStatus(SpreadsheetImport::IMPORTING_STATUS_IN_PROGRESS);
			$spreadsheetImport->setImportingStatus(SpreadsheetImport::IMPORTING_STATUS_IN_PROGRESS);
+6 −5
Original line number Original line Diff line number Diff line
@@ -19,10 +19,11 @@ use Doctrine\ORM\Mapping as ORM;
 */
 */
class SpreadsheetImport {
class SpreadsheetImport {


	const IMPORTING_STATUS_IN_QUEUE = 0;
	const IMPORTING_STATUS_DRAFT = 0;
	const IMPORTING_STATUS_IN_PROGRESS = 1;
	const IMPORTING_STATUS_IN_QUEUE = 1;
	const IMPORTING_STATUS_COMPLETED = 2;
	const IMPORTING_STATUS_IN_PROGRESS = 2;
	const IMPORTING_STATUS_FAILED = 3;
	const IMPORTING_STATUS_COMPLETED = 3;
	const IMPORTING_STATUS_FAILED = 4;


	/**
	/**
	 * @var string
	 * @var string
@@ -72,7 +73,7 @@ class SpreadsheetImport {
	 * @var int
	 * @var int
	 * @ORM\Column(options={"default": 0})
	 * @ORM\Column(options={"default": 0})
	 */
	 */
	protected $importingStatus = self::IMPORTING_STATUS_IN_QUEUE;
	protected $importingStatus = self::IMPORTING_STATUS_DRAFT;


	/**
	/**
	 * @var int
	 * @var int
+16 −2
Original line number Original line Diff line number Diff line
@@ -29,10 +29,10 @@ class SpreadsheetImportRepository extends Repository {
	/**
	/**
	 * @return SpreadsheetImport
	 * @return SpreadsheetImport
	 */
	 */
	public function findPreviousOneInQueue() {
	public function findNextInQueue() {
		$query = $this->createQuery();
		$query = $this->createQuery();
		$constraint = $query->logicalAnd(
		$constraint = $query->logicalAnd(
			$query->equals('importingStatus', SpreadsheetImport::IMPORTING_STATUS_IN_QUEUE),
			$query->lessThanOrEqual('importingStatus', SpreadsheetImport::IMPORTING_STATUS_IN_QUEUE),
			$query->lessThanOrEqual('scheduleDate', new \DateTime())
			$query->lessThanOrEqual('scheduleDate', new \DateTime())
		);
		);
		return $query->matching($constraint)
		return $query->matching($constraint)
@@ -51,4 +51,18 @@ class SpreadsheetImportRepository extends Repository {
		return $query->matching($constraint)->execute();
		return $query->matching($constraint)->execute();
	}
	}


	/**
	 * @param string $context
	 * @param array $arguments
	 *
	 * @return \TYPO3\Flow\Persistence\QueryResultInterface
	 */
	public function findByContextAndArguments($context, $arguments = array()) {
		$query = $this->createQuery();
		$constraint = $query->logicalAnd(
			$query->equals('context', $context),
			$query->equals('arguments', serialize($arguments))
		);
		return $query->matching($constraint)->execute();
	}
}
}
+47 −13
Original line number Original line Diff line number Diff line
@@ -11,42 +11,76 @@ namespace WE\SpreadsheetImport;
 * The TYPO3 project - inspiring people to share!                         *
 * The TYPO3 project - inspiring people to share!                         *
 *                                                                        */
 *                                                                        */


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;


/**
/**
 * Utility 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.
 *
 * @Flow\Scope("singleton")
 */
class FrontendMappingService {

	/**
	 * @Flow\Inject
	 * @var \WE\SpreadsheetImport\SpreadsheetImportService
	 */
	 */
class FrontendMappingUtility {
	protected $spreadsheetImportService;


	/**
	/**
	 * @param \WE\SpreadsheetImport\SpreadsheetImportService $spreadsheetImportService
	 * @Flow\InjectConfiguration
	 * @var array
	 */
	protected $settings;

	/**
	 * @param string $context
	 * @param \TYPO3\Flow\Mvc\ActionRequest $request
	 * @param \TYPO3\Flow\Mvc\ActionRequest $request
	 *
	 *
	 * @return array
	 * @return array
	 */
	 */
	public static function getSpreadsheetImportMappingByRequest(SpreadsheetImportService $spreadsheetImportService, ActionRequest $request) {
	public function getContextArgumentsForRequest($context, ActionRequest $request) {
		$arguments = array();
		$contextArguments = $this->settings[$context]['arguments'];
		if (is_array($contextArguments)) {
			foreach ($contextArguments as $contextArgument) {
				$name = $contextArgument['name'];
				$default = isset($contextArgument['default']) ? $contextArgument['default'] : NULL;
				$arguments[$name] = $request->hasArgument($name) ? $request->getArgument($name) : $default;
			}
		}
		return $arguments;
	}

	/**
	 * @param array $mappingProperties
	 * @param array $columns
	 *
	 * @return array
	 */
	public function getSpreadsheetImportMapping($mappingProperties, $columns = array()) {
		$mappings = array();
		$mappings = array();
		$domainMappingProperties = $spreadsheetImportService->getMappingProperties();
		foreach ($mappingProperties as $property => $mapping) {
		foreach ($domainMappingProperties as $property => $mapping) {
			$column = isset($columns[$property]) ? $columns[$property] : '';
			$column = $request->getArgument($property);
			$columnMapping = array('column' => $column, 'mapping' => $mapping);
			$mappings[$property] = $column;
			$mappings[$property] = $columnMapping;
		}
		}
		return $mappings;
		return $mappings;
	}
	}


	/**
	/**
	 * @param \WE\SpreadsheetImport\SpreadsheetImportService $spreadsheetImportService
	 * @param array $mapping
	 * @param int $record
	 * @param int $record
	 *
	 *
	 * @return array
	 * @return array
	 */
	 */
	public static function getMappingPreview(SpreadsheetImportService $spreadsheetImportService, $record) {
	public function getMappingPreview($mapping, $record) {
		$domainMappingProperties = $spreadsheetImportService->getMappingProperties();
		$previewObject = $this->spreadsheetImportService->getObjectByRow($record);
		$previewObject = $spreadsheetImportService->getObjectByRow($record);
		$preview = array();
		$preview = array();
		foreach ($mapping as $property => $columnMapping) {
			/** @var Mapping $mapping */
			/** @var Mapping $mapping */
		foreach ($domainMappingProperties as $property => $mapping) {
			$mapping = $columnMapping['mapping'];
			$getter = empty($mapping->getter) ? 'get' . ucfirst($property) : $mapping->getter;
			$getter = empty($mapping->getter) ? 'get' . ucfirst($property) : $mapping->getter;
			$preview[$property] = $previewObject->$getter();
			$preview[$property] = $previewObject->$getter();
		}
		}
+63 −72
Original line number Original line Diff line number Diff line
@@ -12,6 +12,7 @@ namespace WE\SpreadsheetImport;
 *                                                                        */
 *                                                                        */


use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Persistence\QueryInterface;
use TYPO3\Flow\Persistence\RepositoryInterface;
use TYPO3\Flow\Persistence\RepositoryInterface;
use WE\SpreadsheetImport\Annotations\Mapping;
use WE\SpreadsheetImport\Annotations\Mapping;
use WE\SpreadsheetImport\Domain\Model\SpreadsheetImport;
use WE\SpreadsheetImport\Domain\Model\SpreadsheetImport;
@@ -20,6 +21,7 @@ use WE\SpreadsheetImport\Domain\Model\SpreadsheetImport;
 * @Flow\Scope("singleton")
 * @Flow\Scope("singleton")
 */
 */
class SpreadsheetImportService {
class SpreadsheetImportService {

	/**
	/**
	 * @var SpreadsheetImport
	 * @var SpreadsheetImport
	 */
	 */
@@ -30,16 +32,6 @@ class SpreadsheetImportService {
	 */
	 */
	protected $domain;
	protected $domain;


	/**
	 * @var array
	 */
	protected $mappingProperties;

	/**
	 * @var array
	 */
	protected $columnPropertyMapping;

	/**
	/**
	 * @Flow\InjectConfiguration
	 * @Flow\InjectConfiguration
	 * @var array
	 * @var array
@@ -76,6 +68,13 @@ class SpreadsheetImportService {
	 */
	 */
	protected $validatorResolver;
	protected $validatorResolver;


	/**
	 * Inverse SpreadsheetImport mapping array
	 *
	 * @var array
	 */
	private $inverseSpreadsheetImportMapping;

	/**
	/**
	 * @param \WE\SpreadsheetImport\Domain\Model\SpreadsheetImport $spreadsheetImport
	 * @param \WE\SpreadsheetImport\Domain\Model\SpreadsheetImport $spreadsheetImport
	 *
	 *
@@ -84,64 +83,20 @@ class SpreadsheetImportService {
	public function init(SpreadsheetImport $spreadsheetImport) {
	public function init(SpreadsheetImport $spreadsheetImport) {
		$this->spreadsheetImport = $spreadsheetImport;
		$this->spreadsheetImport = $spreadsheetImport;
		$this->domain = $this->settings[$spreadsheetImport->getContext()]['domain'];
		$this->domain = $this->settings[$spreadsheetImport->getContext()]['domain'];
		$this->initDomainMappingProperties();
		$this->initColumnPropertyMapping();


		return $this;
		return $this;
	}
	}


	/**
	/**
	 * Initializes the properties declared by annotations.
	 * @return array
	 */
	 */
	private function initDomainMappingProperties() {
	public function getAnnotationMappingProperties() {
		$this->mappingProperties = array();
		$mappingPropertyAnnotations = array();
		$properties = $this->reflectionService->getPropertyNamesByAnnotation($this->domain, Mapping::class);
		$properties = $this->reflectionService->getPropertyNamesByAnnotation($this->domain, Mapping::class);
		foreach ($properties as $property) {
		foreach ($properties as $property) {
			$this->mappingProperties[$property] = $this->reflectionService->getPropertyAnnotation($this->domain, $property, Mapping::class);
			$mappingPropertyAnnotations[$property] = $this->reflectionService->getPropertyAnnotation($this->domain, $property, Mapping::class);
		}
		}
	}
		return $mappingPropertyAnnotations;

	/**
	 * Flip mapping and return it as a 2-dim array in case the same column is assigned to multiple properties
	 */
	private function initColumnPropertyMapping() {
		$this->columnPropertyMapping = array();
		foreach ($this->spreadsheetImport->getMapping() as $property => $column) {
			$this->columnPropertyMapping[$column][] = $property;
		}
	}

	/**
	 * Adds additional mapping properties to the domain mapping properties retrieved by annotations. This increases
	 * flexibility for dynamic property mapping.
	 *
	 * This was implemented for the single use case to support the Flow package Radmiraal.CouchDB
	 *
	 * Note: Those additional property configurations are not persisted and need to be added after each initialization
	 * of the service. The persisted mappings in the SpreadsheetImport object only contain the property without any
	 * configuration. Therefore, the import works but only for the default setters and without identifiers. To support
	 * all, the additional mapping properties need to be persisted together with the mappings.
	 *
	 * @param array $additionalMappingProperties
	 */
	public function addAdditionalMappingProperties(array $additionalMappingProperties) {
		$this->mappingProperties = array_merge($this->mappingProperties, $additionalMappingProperties);
	}

	/**
	 * @return array
	 */
	public function getMappingProperties() {
		return $this->mappingProperties;
	}

	/**
	 * @param string $context
	 *
	 * @return array
	 */
	public function getArgumentsByContext($context) {
		return $this->settings[$context]['arguments'];
	}
	}


	/**
	/**
@@ -274,6 +229,7 @@ class SpreadsheetImportService {
	 * @return array
	 * @return array
	 */
	 */
	private function getDomainMappingIdentifierProperties() {
	private function getDomainMappingIdentifierProperties() {
		// TODO: Don't use the annotation properties but the SpreadsheetImport mapping since we store the Mapping object there as well
		$domainMappingProperties = array();
		$domainMappingProperties = array();
		$properties = $this->reflectionService->getPropertyNamesByAnnotation($this->domain, Mapping::class);
		$properties = $this->reflectionService->getPropertyNamesByAnnotation($this->domain, Mapping::class);
		foreach ($properties as $property) {
		foreach ($properties as $property) {
@@ -298,13 +254,14 @@ class SpreadsheetImportService {
		$spreadsheetImportMapping = $this->spreadsheetImport->getMapping();
		$spreadsheetImportMapping = $this->spreadsheetImport->getMapping();
		/** @var Mapping $mapping */
		/** @var Mapping $mapping */
		foreach ($identifierProperties as $property => $mapping) {
		foreach ($identifierProperties as $property => $mapping) {
			$column = $spreadsheetImportMapping[$property];
			$column = $spreadsheetImportMapping[$property]['column'];
			/** @var \PHPExcel_Worksheet_RowCellIterator $cellIterator */
			/** @var \PHPExcel_Worksheet_RowCellIterator $cellIterator */
			$cellIterator = $row->getCellIterator($column, $column);
			$cellIterator = $row->getCellIterator($column, $column);
			$value = $cellIterator->current()->getValue();
			$value = $cellIterator->current()->getValue();
			$propertyName = $mapping->queryPropertyName ?: $property;
			$propertyName = $mapping->queryPropertyName ?: $property;
			$constraints[] = $query->equals($propertyName, $value);
			$constraints[] = $query->equals($propertyName, $value);
		}
		}
		$this->mergeQueryConstraintsWithArgumentIdentifiers($query, $constraints);
		if (!empty($constraints)) {
		if (!empty($constraints)) {
			return $query->matching($query->logicalAnd($constraints))->execute()->getFirst();
			return $query->matching($query->logicalAnd($constraints))->execute()->getFirst();
		} else {
		} else {
@@ -312,6 +269,26 @@ class SpreadsheetImportService {
		}
		}
	}
	}


	/**
	 * @param \TYPO3\Flow\Persistence\QueryInterface $query
	 * @param array $constraints
	 */
	private function mergeQueryConstraintsWithArgumentIdentifiers(QueryInterface $query, &$constraints) {
		$contextArguments = $this->settings[$this->spreadsheetImport->getContext()]['arguments'];
		if (is_array($contextArguments)) {
			foreach ($contextArguments as $contextArgument) {
				if (isset($contextArgument['identifier']) && $contextArgument['identifier'] == TRUE) {
					$name = $contextArgument['name'];
					$arguments = $this->spreadsheetImport->getArguments();
					if (array_key_exists($name, $arguments)) {
						$value = $arguments[$name];
						$constraints[] = $query->equals($name, $value);
					}
				}
			}
		}
	}

	/**
	/**
	 * @param array $identifiers
	 * @param array $identifiers
	 *
	 *
@@ -328,20 +305,17 @@ class SpreadsheetImportService {
	 * @param \PHPExcel_Worksheet_Row $row
	 * @param \PHPExcel_Worksheet_Row $row
	 */
	 */
	private function setObjectPropertiesByRow($object, $row) {
	private function setObjectPropertiesByRow($object, $row) {
		$domainMappingProperties = $this->mappingProperties;
		$inverseSpreadsheetImportMapping = $this->getInverseSpreadsheetImportMapping();
		/** @var \PHPExcel_Cell $cell */
		/** @var \PHPExcel_Cell $cell */
		foreach ($row->getCellIterator() as $cell) {
		foreach ($row->getCellIterator() as $cell) {
			$column = $cell->getColumn();
			$column = $cell->getColumn();
			if (array_key_exists($column, $this->columnPropertyMapping)) {
			if (array_key_exists($column, $inverseSpreadsheetImportMapping)) {
				$properties = $this->columnPropertyMapping[$column];
				$properties = $inverseSpreadsheetImportMapping[$column];
				foreach ($properties as $property) {
				foreach ($properties as $propertyMapping) {
					if (array_key_exists($property, $domainMappingProperties)) {
					$property = $propertyMapping['property'];
					/** @var Mapping $mapping */
					/** @var Mapping $mapping */
						$mapping = $domainMappingProperties[$property];
					$mapping = $propertyMapping['mapping'];
					$setter = empty($mapping->setter) ? 'set' . ucfirst($property) : $mapping->setter;
					$setter = empty($mapping->setter) ? 'set' . ucfirst($property) : $mapping->setter;
					} else {
						$setter = 'set' . ucfirst($property);
					}
					$object->$setter($cell->getValue());
					$object->$setter($cell->getValue());
				}
				}
			}
			}
@@ -349,11 +323,28 @@ class SpreadsheetImportService {
		$this->setObjectArgumentProperties($object);
		$this->setObjectArgumentProperties($object);
	}
	}


	/**
	 * Return an inverse SpreadsheetImport mapping array. It flips the property and column attribute and returns it as a
	 * 3-dim array instead of a 2-dim array. The reason for that is the case when the same column is assigned to multiple
	 * properties.
	 */
	private function getInverseSpreadsheetImportMapping() {
		if (empty($this->inverseSpreadsheetImportMapping)) {
			$this->inverseSpreadsheetImportMapping = array();
			foreach ($this->spreadsheetImport->getMapping() as $property => $columnMapping) {
				$column = $columnMapping['column'];
				$propertyMapping = array('property' => $property, 'mapping' => $columnMapping['mapping']);
				$this->inverseSpreadsheetImportMapping[$column][] = $propertyMapping;
			}
		}
		return $this->inverseSpreadsheetImportMapping;
	}

	/**
	/**
	 * @param $object
	 * @param $object
	 */
	 */
	private function setObjectArgumentProperties($object) {
	private function setObjectArgumentProperties($object) {
		$contextArguments = $this->getArgumentsByContext($this->spreadsheetImport->getContext());
		$contextArguments = $this->settings[$this->spreadsheetImport->getContext()]['arguments'];
		if (is_array($contextArguments)) {
		if (is_array($contextArguments)) {
			$arguments = $this->spreadsheetImport->getArguments();
			$arguments = $this->spreadsheetImport->getArguments();
			foreach ($contextArguments as $contextArgument) {
			foreach ($contextArguments as $contextArgument) {
Loading