From 88015b311353fdfba463076e4483807907f6e018 Mon Sep 17 00:00:00 2001 From: Abel B Date: Mon, 3 Nov 2025 15:30:23 +0100 Subject: [PATCH 01/21] Add mapping entity to database model and api. --- .../__CG__CSVImportEntityCSVImportEntity.php | 46 +-- .../__CG__CSVImportEntityCSVImportImport.php | 46 +-- .../__CG__CSVImportEntityCSVImportMapping.php | 272 ++++++++++++++++++ src/Api/Adapter/MappingAdapter.php | 51 ++++ .../Representation/MappingRepresentation.php | 55 ++++ 5 files changed, 428 insertions(+), 42 deletions(-) create mode 100644 data/doctrine-proxies/__CG__CSVImportEntityCSVImportMapping.php create mode 100644 src/Api/Adapter/MappingAdapter.php create mode 100644 src/Api/Representation/MappingRepresentation.php diff --git a/data/doctrine-proxies/__CG__CSVImportEntityCSVImportEntity.php b/data/doctrine-proxies/__CG__CSVImportEntityCSVImportEntity.php index 7cbf4b84..85e4b184 100644 --- a/data/doctrine-proxies/__CG__CSVImportEntityCSVImportEntity.php +++ b/data/doctrine-proxies/__CG__CSVImportEntityCSVImportEntity.php @@ -2,6 +2,7 @@ namespace DoctrineProxies\__CG__\CSVImport\Entity; + /** * DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE'S PROXY GENERATOR */ @@ -12,39 +13,41 @@ class CSVImportEntity extends \CSVImport\Entity\CSVImportEntity implements \Doct * three parameters, being respectively the proxy object to be initialized, the method that triggered the * initialization process and an array of ordered parameters that were passed to that method. * - * @see \Doctrine\Common\Persistence\Proxy::__setInitializer + * @see \Doctrine\Common\Proxy\Proxy::__setInitializer */ public $__initializer__; /** * @var \Closure the callback responsible of loading properties that need to be copied in the cloned object * - * @see \Doctrine\Common\Persistence\Proxy::__setCloner + * @see \Doctrine\Common\Proxy\Proxy::__setCloner */ public $__cloner__; /** * @var boolean flag indicating if this object was already initialized * - * @see \Doctrine\Common\Persistence\Proxy::__isInitialized + * @see \Doctrine\Persistence\Proxy::__isInitialized */ public $__isInitialized__ = false; /** - * @var array properties to be lazy loaded, with keys being the property - * names and values being their default values + * @var array properties to be lazy loaded, indexed by property name + */ + public static $lazyPropertiesNames = array ( +); + + /** + * @var array default values of properties to be lazy loaded, with keys being the property names * - * @see \Doctrine\Common\Persistence\Proxy::__getLazyProperties + * @see \Doctrine\Common\Proxy\Proxy::__getLazyProperties */ - public static $lazyPropertiesDefaults = []; + public static $lazyPropertiesDefaults = array ( +); - /** - * @param \Closure $initializer - * @param \Closure $cloner - */ - public function __construct($initializer = null, $cloner = null) + public function __construct(?\Closure $initializer = null, ?\Closure $cloner = null) { $this->__initializer__ = $initializer; @@ -82,7 +85,7 @@ public function __wakeup() $existingProperties = get_object_vars($proxy); - foreach ($proxy->__getLazyProperties() as $property => $defaultValue) { + foreach ($proxy::$lazyPropertiesDefaults as $property => $defaultValue) { if ( ! array_key_exists($property, $existingProperties)) { $proxy->$property = $defaultValue; } @@ -103,7 +106,7 @@ public function __clone() /** * Forces initialization of the proxy */ - public function __load() + public function __load(): void { $this->__initializer__ && $this->__initializer__->__invoke($this, '__load', []); } @@ -112,7 +115,7 @@ public function __load() * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ - public function __isInitialized() + public function __isInitialized(): bool { return $this->__isInitialized__; } @@ -121,7 +124,7 @@ public function __isInitialized() * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ - public function __setInitialized($initialized) + public function __setInitialized($initialized): void { $this->__isInitialized__ = $initialized; } @@ -130,7 +133,7 @@ public function __setInitialized($initialized) * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ - public function __setInitializer(\Closure $initializer = null) + public function __setInitializer(\Closure $initializer = null): void { $this->__initializer__ = $initializer; } @@ -139,7 +142,7 @@ public function __setInitializer(\Closure $initializer = null) * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ - public function __getInitializer() + public function __getInitializer(): ?\Closure { return $this->__initializer__; } @@ -148,7 +151,7 @@ public function __getInitializer() * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ - public function __setCloner(\Closure $cloner = null) + public function __setCloner(\Closure $cloner = null): void { $this->__cloner__ = $cloner; } @@ -157,7 +160,7 @@ public function __setCloner(\Closure $cloner = null) * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific cloning logic */ - public function __getCloner() + public function __getCloner(): ?\Closure { return $this->__cloner__; } @@ -165,9 +168,10 @@ public function __getCloner() /** * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic + * @deprecated no longer in use - generated code now relies on internal components rather than generated public API * @static */ - public function __getLazyProperties() + public function __getLazyProperties(): array { return self::$lazyPropertiesDefaults; } diff --git a/data/doctrine-proxies/__CG__CSVImportEntityCSVImportImport.php b/data/doctrine-proxies/__CG__CSVImportEntityCSVImportImport.php index f985216e..31736f44 100644 --- a/data/doctrine-proxies/__CG__CSVImportEntityCSVImportImport.php +++ b/data/doctrine-proxies/__CG__CSVImportEntityCSVImportImport.php @@ -2,6 +2,7 @@ namespace DoctrineProxies\__CG__\CSVImport\Entity; + /** * DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE'S PROXY GENERATOR */ @@ -12,39 +13,41 @@ class CSVImportImport extends \CSVImport\Entity\CSVImportImport implements \Doct * three parameters, being respectively the proxy object to be initialized, the method that triggered the * initialization process and an array of ordered parameters that were passed to that method. * - * @see \Doctrine\Common\Persistence\Proxy::__setInitializer + * @see \Doctrine\Common\Proxy\Proxy::__setInitializer */ public $__initializer__; /** * @var \Closure the callback responsible of loading properties that need to be copied in the cloned object * - * @see \Doctrine\Common\Persistence\Proxy::__setCloner + * @see \Doctrine\Common\Proxy\Proxy::__setCloner */ public $__cloner__; /** * @var boolean flag indicating if this object was already initialized * - * @see \Doctrine\Common\Persistence\Proxy::__isInitialized + * @see \Doctrine\Persistence\Proxy::__isInitialized */ public $__isInitialized__ = false; /** - * @var array properties to be lazy loaded, with keys being the property - * names and values being their default values + * @var array properties to be lazy loaded, indexed by property name + */ + public static $lazyPropertiesNames = array ( +); + + /** + * @var array default values of properties to be lazy loaded, with keys being the property names * - * @see \Doctrine\Common\Persistence\Proxy::__getLazyProperties + * @see \Doctrine\Common\Proxy\Proxy::__getLazyProperties */ - public static $lazyPropertiesDefaults = []; + public static $lazyPropertiesDefaults = array ( +); - /** - * @param \Closure $initializer - * @param \Closure $cloner - */ - public function __construct($initializer = null, $cloner = null) + public function __construct(?\Closure $initializer = null, ?\Closure $cloner = null) { $this->__initializer__ = $initializer; @@ -82,7 +85,7 @@ public function __wakeup() $existingProperties = get_object_vars($proxy); - foreach ($proxy->__getLazyProperties() as $property => $defaultValue) { + foreach ($proxy::$lazyPropertiesDefaults as $property => $defaultValue) { if ( ! array_key_exists($property, $existingProperties)) { $proxy->$property = $defaultValue; } @@ -103,7 +106,7 @@ public function __clone() /** * Forces initialization of the proxy */ - public function __load() + public function __load(): void { $this->__initializer__ && $this->__initializer__->__invoke($this, '__load', []); } @@ -112,7 +115,7 @@ public function __load() * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ - public function __isInitialized() + public function __isInitialized(): bool { return $this->__isInitialized__; } @@ -121,7 +124,7 @@ public function __isInitialized() * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ - public function __setInitialized($initialized) + public function __setInitialized($initialized): void { $this->__isInitialized__ = $initialized; } @@ -130,7 +133,7 @@ public function __setInitialized($initialized) * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ - public function __setInitializer(\Closure $initializer = null) + public function __setInitializer(\Closure $initializer = null): void { $this->__initializer__ = $initializer; } @@ -139,7 +142,7 @@ public function __setInitializer(\Closure $initializer = null) * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ - public function __getInitializer() + public function __getInitializer(): ?\Closure { return $this->__initializer__; } @@ -148,7 +151,7 @@ public function __getInitializer() * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic */ - public function __setCloner(\Closure $cloner = null) + public function __setCloner(\Closure $cloner = null): void { $this->__cloner__ = $cloner; } @@ -157,7 +160,7 @@ public function __setCloner(\Closure $cloner = null) * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific cloning logic */ - public function __getCloner() + public function __getCloner(): ?\Closure { return $this->__cloner__; } @@ -165,9 +168,10 @@ public function __getCloner() /** * {@inheritDoc} * @internal generated method: use only when explicitly handling proxy specific loading logic + * @deprecated no longer in use - generated code now relies on internal components rather than generated public API * @static */ - public function __getLazyProperties() + public function __getLazyProperties(): array { return self::$lazyPropertiesDefaults; } diff --git a/data/doctrine-proxies/__CG__CSVImportEntityCSVImportMapping.php b/data/doctrine-proxies/__CG__CSVImportEntityCSVImportMapping.php new file mode 100644 index 00000000..430878ab --- /dev/null +++ b/data/doctrine-proxies/__CG__CSVImportEntityCSVImportMapping.php @@ -0,0 +1,272 @@ + properties to be lazy loaded, indexed by property name + */ + public static $lazyPropertiesNames = array ( +); + + /** + * @var array default values of properties to be lazy loaded, with keys being the property names + * + * @see \Doctrine\Common\Proxy\Proxy::__getLazyProperties + */ + public static $lazyPropertiesDefaults = array ( +); + + + + public function __construct(?\Closure $initializer = null, ?\Closure $cloner = null) + { + + $this->__initializer__ = $initializer; + $this->__cloner__ = $cloner; + } + + + + + + + + /** + * + * @return array + */ + public function __sleep() + { + if ($this->__isInitialized__) { + return ['__isInitialized__', 'id', 'name', 'created', 'mapping']; + } + + return ['__isInitialized__', 'id', 'name', 'created', 'mapping']; + } + + /** + * + */ + public function __wakeup() + { + if ( ! $this->__isInitialized__) { + $this->__initializer__ = function (CSVImportMapping $proxy) { + $proxy->__setInitializer(null); + $proxy->__setCloner(null); + + $existingProperties = get_object_vars($proxy); + + foreach ($proxy::$lazyPropertiesDefaults as $property => $defaultValue) { + if ( ! array_key_exists($property, $existingProperties)) { + $proxy->$property = $defaultValue; + } + } + }; + + } + } + + /** + * + */ + public function __clone() + { + $this->__cloner__ && $this->__cloner__->__invoke($this, '__clone', []); + } + + /** + * Forces initialization of the proxy + */ + public function __load(): void + { + $this->__initializer__ && $this->__initializer__->__invoke($this, '__load', []); + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __isInitialized(): bool + { + return $this->__isInitialized__; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __setInitialized($initialized): void + { + $this->__isInitialized__ = $initialized; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __setInitializer(\Closure $initializer = null): void + { + $this->__initializer__ = $initializer; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __getInitializer(): ?\Closure + { + return $this->__initializer__; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + */ + public function __setCloner(\Closure $cloner = null): void + { + $this->__cloner__ = $cloner; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific cloning logic + */ + public function __getCloner(): ?\Closure + { + return $this->__cloner__; + } + + /** + * {@inheritDoc} + * @internal generated method: use only when explicitly handling proxy specific loading logic + * @deprecated no longer in use - generated code now relies on internal components rather than generated public API + * @static + */ + public function __getLazyProperties(): array + { + return self::$lazyPropertiesDefaults; + } + + + /** + * {@inheritDoc} + */ + public function getId() + { + if ($this->__isInitialized__ === false) { + return (int) parent::getId(); + } + + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getId', []); + + return parent::getId(); + } + + /** + * {@inheritDoc} + */ + public function getName() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getName', []); + + return parent::getName(); + } + + /** + * {@inheritDoc} + */ + public function setName($name) + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setName', [$name]); + + return parent::setName($name); + } + + /** + * {@inheritDoc} + */ + public function getMapping() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getMapping', []); + + return parent::getMapping(); + } + + /** + * {@inheritDoc} + */ + public function setMapping($mapping) + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'setMapping', [$mapping]); + + return parent::setMapping($mapping); + } + + /** + * {@inheritDoc} + */ + public function getCreated() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getCreated', []); + + return parent::getCreated(); + } + + /** + * {@inheritDoc} + */ + public function prePersist(\Doctrine\ORM\Event\LifecycleEventArgs $eventArgs) + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'prePersist', [$eventArgs]); + + return parent::prePersist($eventArgs); + } + + /** + * {@inheritDoc} + */ + public function getResourceId() + { + + $this->__initializer__ && $this->__initializer__->__invoke($this, 'getResourceId', []); + + return parent::getResourceId(); + } + +} diff --git a/src/Api/Adapter/MappingAdapter.php b/src/Api/Adapter/MappingAdapter.php new file mode 100644 index 00000000..475d9175 --- /dev/null +++ b/src/Api/Adapter/MappingAdapter.php @@ -0,0 +1,51 @@ +getContent(); + + if (isset($data['name'])) { + $entity->setName($data['name']); + } + + if (isset($data['mapping'])) { + $entity->setMapping($data['mapping']); + } + } + + public function validateEntity(EntityInterface $entity, ErrorStore $errorStore) + { + if (!$entity->getName()) { + $errorStore->addError('o-module-csvimport-mapping:name', 'A model must have a name to save it.'); // @translate + } + + if (!$entity->getMapping()) { + $errorStore->addError('o-module-csvimport-mapping:mapping', 'Mapping must exists.'); // @translate + } + } +} diff --git a/src/Api/Representation/MappingRepresentation.php b/src/Api/Representation/MappingRepresentation.php new file mode 100644 index 00000000..a0522b74 --- /dev/null +++ b/src/Api/Representation/MappingRepresentation.php @@ -0,0 +1,55 @@ + $this->name(), + 'mapping' => $this->mapping(), + 'created' => $this->created(), + ]; + } + + public function getJsonLdType() + { + return 'o:CSVimportMapping'; + } + + public function name() + { + return $this->resource->getName(); + } + + public function mapping() + { + return $this->resource->getMapping(); + } + + public function created() + { + return $this->resource->getCreated(); + } + + public function adminUrl($action = null, $canonical = false) + { + $url = $this->getViewHelper('Url'); + return $url( + 'admin/csvimport/mapping-id', + [ + 'controller' => $this->getControllerName(), + 'action' => $action, + 'id' => $this->id(), + ], + ['force_canonical' => $canonical] + ); + } +} From 68f6a904d1d896a6de01779cb5b18f114a40ca57 Mon Sep 17 00:00:00 2001 From: Abel B Date: Mon, 3 Nov 2025 15:33:00 +0100 Subject: [PATCH 02/21] Add entity file to last commit. --- src/Entity/CSVImportMapping.php | 79 +++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/Entity/CSVImportMapping.php diff --git a/src/Entity/CSVImportMapping.php b/src/Entity/CSVImportMapping.php new file mode 100644 index 00000000..9ba5f65b --- /dev/null +++ b/src/Entity/CSVImportMapping.php @@ -0,0 +1,79 @@ +id; + } + + public function getName() + { + return $this->name; + } + + public function setName($name) + { + $this->name = $name; + + return $this; + } + + public function getMapping() + { + return $this->mapping; + } + + public function setMapping($mapping) + { + $this->mapping = $mapping; + + return $this; + } + + public function getCreated() + { + return $this->created; + } + + /** + * @PrePersist + */ + public function prePersist(LifecycleEventArgs $eventArgs) + { + $this->created = new DateTime('now'); + } +} \ No newline at end of file From 03535ee2454000175b818ad04140cabe7f08ab8c Mon Sep 17 00:00:00 2001 From: Abel B Date: Mon, 3 Nov 2025 15:37:24 +0100 Subject: [PATCH 03/21] Add save/load mapping functions to IndexController. --- src/Controller/IndexController.php | 71 ++++++- src/Mvc/Controller/Plugin/LoadMapping.php | 187 ++++++++++++++++++ .../ControllerPlugin/LoadMappingFactory.php | 18 ++ 3 files changed, 274 insertions(+), 2 deletions(-) create mode 100644 src/Mvc/Controller/Plugin/LoadMapping.php create mode 100644 src/Service/ControllerPlugin/LoadMappingFactory.php diff --git a/src/Controller/IndexController.php b/src/Controller/IndexController.php index 3e3073b2..532bffe2 100644 --- a/src/Controller/IndexController.php +++ b/src/Controller/IndexController.php @@ -123,6 +123,11 @@ public function mapAction() return $this->redirect()->toRoute('admin/csvimport'); } + $session = new \Laminas\Session\Container('CsvImport'); + + $session->columns = $columns; + $session->resourceType = $resourceType; + $mappingOptions['columns'] = $columns; $form = $this->getForm(MappingForm::class, $mappingOptions); @@ -130,7 +135,16 @@ public function mapAction() $automapOptions['check_names_alone'] = $args['automap_check_names_alone']; $automapOptions['format'] = 'form'; - $autoMaps = $this->automapHeadersToMetadata($columns, $resourceType, $automapOptions); + $autoMaps = []; + if (isset($post['mapping_id'])) { + $this->logger()->debug("Received mapping id."); + $autoMaps = $this->loadMapping($post['mapping_id'], + $columns, + $this->automapHeadersToMetadata($columns, $resourceType, $automapOptions)); + } + if (empty($autoMaps)) { + $autoMaps = $this->automapHeadersToMetadata($columns, $resourceType, $automapOptions); + } $view->setVariable('form', $form); $view->setVariable('resourceType', $resourceType); @@ -143,7 +157,9 @@ public function mapAction() $view->setVariable('mappings', $this->getMappingsForResource($resourceType)); $view->setVariable('mediaForms', $this->getMediaForms()); $view->setVariable('dataTypes', $this->getDataTypes()); + return $view; + } else { $form = $this->getForm(MappingForm::class, $mappingOptions); $form->setData($post); @@ -156,6 +172,7 @@ public function mapAction() $args = $this->cleanArgs($post); $this->saveUserSettings($args); + $this->saveMapping($args, []); $dispatcher = $this->jobDispatcher(); $job = $dispatcher->dispatch('CSVImport\Job\Import', $args); // The CsvImport record is created in the job, so it doesn't @@ -458,4 +475,54 @@ protected function saveUserSettings(array $settings) } } } -} + + /** + * Save mapping. + * + */ + protected function saveMapping(array $args): void + { + // We first need to read the file to get the column names + // Because we need to remember the column names + $filePath = $args['filepath']; + + // Check if file exists and is readable + if (!file_exists($filePath) || !is_readable($filePath)) { + $this->logger()->err(sprintf("[CSV Import]: File '%s' not found when saving mapping.", $filePath)); // @translate + } + + // Open the file for reading + if (($handle = fopen($filePath, 'r')) !== false) { + // Read the first line as CSV (header row) + $args['columns'] = fgetcsv($handle); + + // Close file + fclose($handle); + + // Output the column names + if (!$args['columns']) { + $this->logger()->err(sprintf("[CSV Import]: Unable to read columns when saving mapping.")); // @translate + } + } else { + $this->logger()->err(sprintf("[CSV Import]: File '%s' could not be opened when saving mapping.", $filePath)); // @translate + } + + if (empty($args['columns'])) { + $this->logger()->err(sprintf("[CSV Import]: Unable to get columns from file '%s'.", $filePath)); // @translate + } + + $this->logger()->debug(sprintf("[CSV Import] Column names: " . PHP_EOL . "%s" . PHP_EOL, json_encode($args["columns"]))); + + // don't save irrelevant data + unset($args['filename']); + unset($args['filesize']); + unset($args['filepath']); + unset($args['media_type']); + unset($args['resource_type']); + unset($args['automap_check_names_alone']); + + $this->logger()->debug(sprintf('[CSV Import: Args to be saved my mapping]' . PHP_EOL . '%s' . PHP_EOL, json_encode($args))); + + $this->api()->create('csvimport_mappings', ['mapping' => json_encode($args), 'name' => 'Mapping']); + } +} \ No newline at end of file diff --git a/src/Mvc/Controller/Plugin/LoadMapping.php b/src/Mvc/Controller/Plugin/LoadMapping.php new file mode 100644 index 00000000..b3d2404e --- /dev/null +++ b/src/Mvc/Controller/Plugin/LoadMapping.php @@ -0,0 +1,187 @@ +connection = $connection; + $this->api = $apiManager; + $this->logger = $logger; + } + + /** + * + */ + public function __invoke(int $id, array $columns, array $defaultAutomap) + { + // Fetch the mapping + $mapping = $this->api->read('csvimport_mappings', $id)->getContent(); + + if (empty($mapping)) { + // $this->logger()->debug(sprintf('No mapping with id %s found.', $id)); + return []; + } + + $mappingValue = json_decode($mapping->mapping(), true); + + $originalColumns = $mappingValue['columns']; + unset($mappingValue['columns']); // so we don't iterate over it after like it's an actual mapping + + // $this->logger->debug(sprintf('Old columns : ' . PHP_EOL . '%s' . PHP_EOL . 'New columns:' . PHP_EOL . '%s' . PHP_EOL, + // json_encode($originalColumns), json_encode($columns))); + + // Find the mapping between old column indexes and current columns, according to name matching + $oldToNewColumn = []; + if (!empty($columns)) { + foreach ($columns as $index => $column) { + $columnMapping = array_search($column, $originalColumns); + + if ($columnMapping !== false) { + $oldToNewColumn[strval($columnMapping)] = $index; + } + } + } + else { + foreach ($originalColumns as $index => $column) { + $oldToNewColumn[strval($index)] = $index; + } + } + + // $this->logger->debug(sprintf('Column mapping: ' . PHP_EOL . '%s' . PHP_EOL, json_encode($oldToNewColumn))); + // $this->logger->debug(sprintf('Mapping in : ' . PHP_EOL . '%s' . PHP_EOL, json_encode($mappingValue))); + + $automap = []; + + // if no columns passed as argument it means there are no new columns, so we remind of the original ones + // used in MappingController + if (empty($columns)) { + $automap['columns'] = $originalColumns; + } + + /* + * Reading each entry that was sent by the user in the form + * The structure is complicated and undocumented. + */ + foreach ($mappingValue as $mappingValueColumnName => $mappingValueColumn) { + $name = ""; + if (str_contains($mappingValueColumnName, 'column-')) { + $name = explode('column-', $mappingValueColumnName)[1]; + + // properties of type property + if ($name == 'property') { + foreach ($mappingValueColumn as $index => $property) { + if (array_key_exists($index, $oldToNewColumn)) { + foreach ($property as $subindex => $subproperty) { + $element = []; + $element["name"] = $name; + $element["class"] = $name; + $element["multiple"] = true; + $element["special"] = " data-property-id=\"" . $subproperty . "\""; + $element["label"] = explode(':', $subindex)[1] ?? $subindex; + $element["value"] = $subproperty; + $automap[$oldToNewColumn[$index]][] = $element; + } + } + } + } + + // these are column options. Only one per column, for data simplicity we put it in $automap[ColumnIndex][0] + else if ($name == "data-type" + || $name == "multivalue" + || $name == "language" + || $name == "private-values" + || $name == "resource-identifier-property") { + foreach ($mappingValueColumn as $index => $property) { + if (array_key_exists($index, $oldToNewColumn)) { + $automap[$oldToNewColumn[$index]][0][$name] = $property; + } + } + } + + // these are mappings that are other than properties + else { + foreach ($mappingValueColumn as $index => $property) { + if (array_key_exists($index, $oldToNewColumn)) { + $element = []; + $element["name"] = $name; + $element["class"] = $name; + $element["multiple"] = false; + $element["special"] = ""; + $element["value"] = $property; + $element["label"] = "label"; // @tdodo + $automap[$oldToNewColumn[$index]][] = $element; + } + } + } + } + + } + + // default automap may be empty + /* + foreach ($defaultAutomap as $index => $property) { + if (!array_key_exists($index, $automap)) { + $automap[$index][] = $property; + } + } + */ + + // $this->logger->debug(sprintf("[Mapping loaded]" . PHP_EOL . "%s" . PHP_EOL, json_encode($automap))); + + return $automap; + } +} diff --git a/src/Service/ControllerPlugin/LoadMappingFactory.php b/src/Service/ControllerPlugin/LoadMappingFactory.php new file mode 100644 index 00000000..fad56162 --- /dev/null +++ b/src/Service/ControllerPlugin/LoadMappingFactory.php @@ -0,0 +1,18 @@ +get('Omeka\Connection'), + $services->get('Omeka\ApiManager'), + $services->get('Omeka\Logger') + ); + } +} From 4d94a89f6e0d26d1b77330bc8da89cf711b1cc3c Mon Sep 17 00:00:00 2001 From: Abel B Date: Mon, 3 Nov 2025 15:38:33 +0100 Subject: [PATCH 04/21] Separate views for mapping table and the rest. --- view/common/mapping-table.phtml | 87 +++++++++++++++++++++++++++ view/csv-import/index/map.phtml | 100 +++++++++----------------------- 2 files changed, 114 insertions(+), 73 deletions(-) create mode 100644 view/common/mapping-table.phtml diff --git a/view/common/mapping-table.phtml b/view/common/mapping-table.phtml new file mode 100644 index 00000000..2e94adb7 --- /dev/null +++ b/view/common/mapping-table.phtml @@ -0,0 +1,87 @@ +plugin('escapeHtml'); ?> + + + + + + + + + + $column): ?> + + + + + + + +
+ + + + translate("Column"); ?> + translate("Mappings"); ?>translate("Options"); ?>
+ + + + +
    +
  • + +
  • + +
+
+
    + + + +
  • > + translate($automaps[$index]['label']); ?> +
      +
    • +
    + +
  • + + +
  • > + translate($automap['label']); ?> +
      +
    • +
    + +
  • + + + +
+
+
    +
  • + translate('Data type:'); ?> + + > +
  • +
  • + translate("Multivalue"); ?> + " > +
  • +
  • + translate("Language:"); ?> + + > +
  • +
  • + translate("Private values"); ?> + " > +
  • +
  • + translate("Resource identifier property:"); ?> + + > +
  • +
+
\ No newline at end of file diff --git a/view/csv-import/index/map.phtml b/view/csv-import/index/map.phtml index f310f84d..cc74c884 100644 --- a/view/csv-import/index/map.phtml +++ b/view/csv-import/index/map.phtml @@ -4,6 +4,7 @@ $escapeHtml = $this->plugin('escapeHtml'); $this->htmlElement('body')->appendAttribute('class', 'no-section-hashes'); $this->headLink()->appendStylesheet($this->assetUrl('css/csvimport.css', 'CSVImport')); $this->headScript()->appendFile($this->assetUrl('js/csvimport.js', 'CSVImport')); +$this->headScript()->appendFile($this->assetUrl('js/mappingselect.js', 'CSVImport')); $resourceTypeLabels = [ 'items' => $this->translate('items'), @@ -39,6 +40,21 @@ $pageTitle = isset($resourceTypeLabels[$resourceType]) formCollection($form); ?>
+ hyperlink( + '', + '#', + [ + 'data-sidebar-content-url' => $this->url('admin/csvimport/mapping', + [ + 'controller' => 'Mapping', + 'action' => 'selectMapping', + ] + ), + 'class' => 'button sidebar-content', + 'title' => $this->translate('Select mapping'), + 'data-sidebar-selector' => '#sidebar', + ] + ); ?>
@@ -59,82 +75,20 @@ $pageTitle = isset($resourceTypeLabels[$resourceType]) translate('Batch edit options'); ?>
- - - - - - - - - - $column): ?> - - - - - - - -
- - - - translate("Column"); ?> - translate("Mappings"); ?>translate("Options"); ?>
- - - - -
    -
  • - -
  • - -
-
-
    - - -
  • > - translate($automaps[$index]['label']); ?> -
      -
    • -
    - -
  • - -
-
-
    -
  • - translate('Data type:'); ?> - - -
  • -
  • - translate("Multivalue"); ?> - -
  • -
  • - translate("Language:"); ?> - - -
  • -
  • - translate("Private values"); ?> - -
  • -
  • - translate("Resource identifier property:"); ?> - - -
  • -
-
+ partial('common/mapping-table', ['resourceType' => $resourceType, 'columns' => $columns, 'automaps' => $automaps]); ?> partial('common/mapping-sidebar'); ?> partial('common/options-sidebar', ['dataTypes' => $dataTypes]); ?>
form()->closeTag($form); ?> + + + From 3b472ee166a29f34837fc134f88dad55dbe93e4f Mon Sep 17 00:00:00 2001 From: Abel B Date: Mon, 3 Nov 2025 15:39:03 +0100 Subject: [PATCH 05/21] Change module version and database schema in Module.php --- Module.php | 35 +++++++++++++++-------------------- config/module.ini | 2 +- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/Module.php b/Module.php index f6b0c49f..c5764f58 100644 --- a/Module.php +++ b/Module.php @@ -21,26 +21,9 @@ public function install(ServiceLocatorInterface $serviceLocator) { $connection = $serviceLocator->get('Omeka\Connection'); $sql = <<<'SQL' -CREATE TABLE csvimport_import ( - id INT AUTO_INCREMENT NOT NULL, - job_id INT NOT NULL, - undo_job_id INT DEFAULT NULL, - comment VARCHAR(255) DEFAULT NULL, - resource_type VARCHAR(255) NOT NULL, - has_err TINYINT(1) NOT NULL, - stats LONGTEXT NOT NULL COMMENT '(DC2Type:json_array)', - UNIQUE INDEX UNIQ_17B50881BE04EA9 (job_id), - UNIQUE INDEX UNIQ_17B508814C276F75 (undo_job_id), - PRIMARY KEY(id) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB; -CREATE TABLE csvimport_entity ( - id INT AUTO_INCREMENT NOT NULL, - job_id INT NOT NULL, - entity_id INT NOT NULL, - resource_type VARCHAR(255) NOT NULL, - INDEX IDX_84D382F4BE04EA9 (job_id), - PRIMARY KEY(id) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB; +CREATE TABLE csvimport_mapping (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, created DATETIME NOT NULL, mapping LONGTEXT NOT NULL COMMENT '(DC2Type:json)', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; +CREATE TABLE csvimport_import (id INT AUTO_INCREMENT NOT NULL, job_id INT NOT NULL, undo_job_id INT DEFAULT NULL, comment VARCHAR(255) DEFAULT NULL, resource_type VARCHAR(255) NOT NULL, has_err TINYINT(1) NOT NULL, stats LONGTEXT NOT NULL COMMENT '(DC2Type:json_array)', UNIQUE INDEX UNIQ_17B50881BE04EA9 (job_id), UNIQUE INDEX UNIQ_17B508814C276F75 (undo_job_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; +CREATE TABLE csvimport_entity (id INT AUTO_INCREMENT NOT NULL, job_id INT NOT NULL, entity_id INT NOT NULL, resource_type VARCHAR(255) NOT NULL, INDEX IDX_84D382F4BE04EA9 (job_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; ALTER TABLE csvimport_import ADD CONSTRAINT FK_17B50881BE04EA9 FOREIGN KEY (job_id) REFERENCES job (id); ALTER TABLE csvimport_import ADD CONSTRAINT FK_17B508814C276F75 FOREIGN KEY (undo_job_id) REFERENCES job (id); ALTER TABLE csvimport_entity ADD CONSTRAINT FK_84D382F4BE04EA9 FOREIGN KEY (job_id) REFERENCES job (id); @@ -60,6 +43,7 @@ public function uninstall(ServiceLocatorInterface $serviceLocator) ALTER TABLE csvimport_import DROP FOREIGN KEY FK_17B50881BE04EA9; DROP TABLE IF EXISTS csvimport_entity; DROP TABLE IF EXISTS csvimport_import; +DROP TABLE IF EXISTS csvimport_mapping; SQL; $sqls = array_filter(array_map('trim', explode(';', $sql))); foreach ($sqls as $sql) { @@ -76,6 +60,17 @@ public function upgrade($oldVersion, $newVersion, ServiceLocatorInterface $servi ALTER TABLE csvimport_import ADD stats LONGTEXT NOT NULL COMMENT '(DC2Type:json_array)'; UPDATE csvimport_import SET stats = CONCAT('{"processed":{"', resource_type, '":', added_count, '}}'); ALTER TABLE csvimport_import DROP added_count; +SQL; + $sqls = array_filter(array_map('trim', explode(';', $sql))); + foreach ($sqls as $sql) { + $connection->exec($sql); + } + } + + if (version_compare($oldVersion, '2.7.0', '<')) { + $connection = $serviceLocator->get('Omeka\Connection'); + $sql = <<<'SQL' +CREATE TABLE csvimport_entity (id INT AUTO_INCREMENT NOT NULL, job_id INT NOT NULL, entity_id INT NOT NULL, resource_type VARCHAR(255) NOT NULL, INDEX IDX_84D382F4BE04EA9 (job_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; SQL; $sqls = array_filter(array_map('trim', explode(';', $sql))); foreach ($sqls as $sql) { diff --git a/config/module.ini b/config/module.ini index 4a035b55..781ee70f 100644 --- a/config/module.ini +++ b/config/module.ini @@ -8,5 +8,5 @@ author_link = "https://omeka.org/" module_link = "https://omeka.org/s/docs/user-manual/modules/csvimport/" support_link = "https://forum.omeka.org/c/omeka-s/modules" configurable = false -version = "2.6.2" +version = "2.7.0" omeka_version_constraint = "^4.0.0" From d447361c6b2e3cf3525521e565fc2ff5580a135c Mon Sep 17 00:00:00 2001 From: Abel B Date: Mon, 3 Nov 2025 15:41:01 +0100 Subject: [PATCH 06/21] Add controllers for saved mappings and interface. --- src/Controller/Admin/MappingController.php | 175 ++++++++++++++++++ src/Form/Element/MappingSelect.php | 38 ++++ src/Form/MappingEditForm.php | 22 +++ src/Form/MappingSelectForm.php | 34 ++++ .../Admin/MappingControllerFactory.php | 17 ++ .../Form/Element/MappingSelectFactory.php | 16 ++ view/csv-import/admin/mapping/browse.phtml | 117 ++++++++++++ view/csv-import/admin/mapping/edit.phtml | 14 ++ .../admin/mapping/select-mapping.phtml | 16 ++ view/csv-import/admin/mapping/show.phtml | 65 +++++++ 10 files changed, 514 insertions(+) create mode 100644 src/Controller/Admin/MappingController.php create mode 100644 src/Form/Element/MappingSelect.php create mode 100644 src/Form/MappingEditForm.php create mode 100644 src/Form/MappingSelectForm.php create mode 100644 src/Service/Controller/Admin/MappingControllerFactory.php create mode 100644 src/Service/Form/Element/MappingSelectFactory.php create mode 100644 view/csv-import/admin/mapping/browse.phtml create mode 100644 view/csv-import/admin/mapping/edit.phtml create mode 100644 view/csv-import/admin/mapping/select-mapping.phtml create mode 100644 view/csv-import/admin/mapping/show.phtml diff --git a/src/Controller/Admin/MappingController.php b/src/Controller/Admin/MappingController.php new file mode 100644 index 00000000..dbf01a16 --- /dev/null +++ b/src/Controller/Admin/MappingController.php @@ -0,0 +1,175 @@ +setBrowseDefaults('created'); + $response = $this->api()->search('csvimport_mappings'); + + $this->paginator($response->getTotalResults()); + + $formDeleteSelected = $this->getForm(ConfirmForm::class); + $formDeleteSelected->setAttribute('action', $this->url()->fromRoute(null, ['action' => 'batch-delete'], true)); + $formDeleteSelected->setButtonLabel('Confirm Delete'); // @translate + $formDeleteSelected->setAttribute('id', 'confirm-delete-selected'); + + $view = new ViewModel; + $mappingModels = $response->getContent(); + $view->setVariable('mappingModels', $mappingModels); + $view->setVariable('formDeleteSelected', $formDeleteSelected); + return $view; + } + + public function showAction() + { + $propertiesMap = []; + $properties = $this->api()->search('properties')->getContent(); + foreach ($properties as $property) { + $propertiesMap[$property->id()] = $property->term(); + } + + $mappingModel = $this->loadMapping($this->params('id'), [], []); + + $view = new ViewModel; + $view->setVariable('propertiesMap', $propertiesMap); + $view->setVariable('columns', $mappingModel['columns']); + unset( $mappingModel['columns']); + $this->logger()->debug(json_encode($mappingModel)); + $view->setVariable('automaps', $mappingModel); + return $view; + } + + /* + * meant for JS + */ + public function selectMappingAction() + { + $response = $this->api()->search('csvimport_mappings'); + $mappings = $response->getContent(); + + $view = new ViewModel; + $form = $this->getForm(MappingSelectForm::class); + $view->setVariable('form', $form); + $view->setTerminal(true); + $view->setTemplate('csv-import/admin/mapping/select-mapping'); + + if ($this->getRequest()->isPost()) { + $data = $this->params()->fromPost(); + $form->setData($data); + if ($form->isValid()) { + $mappingId = $form->get('mapping_id')->getValue(); + + $session = new \Laminas\Session\Container('CsvImport'); + + $columns = $session->columns; + + $response = $this->api()->read('csvimport_mappings', $mappingId); + if ($response) { + $view = new ViewModel([ + 'automaps' => $this->loadMapping($mappingId, $columns, []), + 'columns' => $columns, + 'resourceType' => $session->resourceType + ]); + $view->setTemplate('common/mapping-table'); + $view->setTerminal(true); // no layout + return $view; + } + else { + return $this->getResponse()->setStatusCode(404)->setContent('Mapping not found.'); // @translate + } + } + return $this->getResponse()->setStatusCode(400)->setContent('Mapping selection form not valid.'); + } + + return $view; + } + + public function editAction() + { + $response = $this->api()->read('csvimport_mappings', $this->params('id')); + $mapping = $response->getContent(); + + $view = new ViewModel; + $form = $this->getForm(MappingEditForm::class); + $form->setAttribute('action', $mapping->url('edit')); + $form->setData([ + 'model_name' => $mapping->name(), + ]); + + $view->setVariable('form', $form); + $view->setTerminal(true); + $view->setTemplate('csv-import/admin/mapping/edit'); + $view->setVariable('mapping', $mapping); + + if ($this->getRequest()->isPost()) { + $data = $this->params()->fromPost(); + $form->setData($data); + if ($form->isValid()) { + $mappingName = $form->get('model_name')->getValue(); + + $response = $this->api($form)->update('csvimport_mappings', $this->params('id'), ['name' => $mappingName], [], ['isPartial' => true]); + if ($response) { + $this->messenger()->addSuccess('Mapping successfully updated'); // @translate + return $this->redirect()->toRoute( + 'admin/csvimport/mapping', + ['action' => 'browse'], + true + ); + } + } else { + $this->messenger()->addFormErrors($form); + return $this->redirect()->toRoute( + 'admin/csvimport/mapping', + ['action' => 'browse'], + true + ); + } + } + return $view; + } + + public function deleteConfirmAction() + { + $response = $this->api()->read('csvimport_mappings', $this->params('id')); + $mappingModel = $response->getContent(); + + $view = new ViewModel; + $view->setTerminal(true); + $view->setTemplate('common/delete-confirm-details'); + $view->setVariable('resource', $mappingModel); + // $view->setVariable('partialPath', '...') + $view->setVariable('resourceLabel', 'Mapping'); // @translate + return $view; + } + + public function deleteAction() + { + if ($this->getRequest()->isPost()) { + $form = $this->getForm(ConfirmForm::class); + $form->setData($this->getRequest()->getPost()); + if ($form->isValid()) { + $response = $this->api($form)->delete('csvimport_mappings', $this->params('id')); + if ($response) { + $this->messenger()->addSuccess('Mapping successfully deleted'); // @translate + } + } else { + $this->messenger()->addFormErrors($form); + } + } + return $this->redirect()->toRoute( + 'admin/csvimport/mapping', + ['action' => 'browse'], + true + ); + } +} diff --git a/src/Form/Element/MappingSelect.php b/src/Form/Element/MappingSelect.php new file mode 100644 index 00000000..1a1cfebd --- /dev/null +++ b/src/Form/Element/MappingSelect.php @@ -0,0 +1,38 @@ +apiManager = $apiManager; + } + + /** + * @return ApiManager + */ + public function getApiManager() + { + return $this->apiManager; + } + + public function getValueOptions(): array + { + $valueOptions = []; + $mappings = $this->apiManager->search("csvimport_mappings", [])->getContent(); + foreach ($mappings as $mapping) { + $valueOptions[$mapping->id()] = $mapping->name(); + } + return $valueOptions; + } +} diff --git a/src/Form/MappingEditForm.php b/src/Form/MappingEditForm.php new file mode 100644 index 00000000..82d907aa --- /dev/null +++ b/src/Form/MappingEditForm.php @@ -0,0 +1,22 @@ +add([ + 'name' => 'model_name', + 'type' => 'text', + 'options' => [ + 'label' => 'Mapping model name', //@translate + ], + 'attributes' => [ + 'required' => true, + ], + ]); + } +} diff --git a/src/Form/MappingSelectForm.php b/src/Form/MappingSelectForm.php new file mode 100644 index 00000000..8a78ed95 --- /dev/null +++ b/src/Form/MappingSelectForm.php @@ -0,0 +1,34 @@ +setAttribute('action', '/admin/csvimport/mapping/selectMapping'); + + $this->add([ + 'name' => 'mapping_id', + 'type' => MappingSelect::class, + 'attributes' => [ + 'id' => 'mapping-id', + 'class' => 'chosen-select', + 'multiple' => false, + 'data-placeholder' => '', + ], + 'options' => [ + 'label' => 'Select mapping', // @translate + 'resource_value_options' => [ + 'resource' => 'csvimport_mappings', + 'query' => [], + ], + ], + ]); + } +} \ No newline at end of file diff --git a/src/Service/Controller/Admin/MappingControllerFactory.php b/src/Service/Controller/Admin/MappingControllerFactory.php new file mode 100644 index 00000000..c0a3d4d7 --- /dev/null +++ b/src/Service/Controller/Admin/MappingControllerFactory.php @@ -0,0 +1,17 @@ +setApiManager($services->get('Omeka\ApiManager')); + return $element; + } +} diff --git a/view/csv-import/admin/mapping/browse.phtml b/view/csv-import/admin/mapping/browse.phtml new file mode 100644 index 00000000..2f8d4c8e --- /dev/null +++ b/view/csv-import/admin/mapping/browse.phtml @@ -0,0 +1,117 @@ +plugin('translate'); +$escape = $this->plugin('escapeHtml'); +$this->htmlElement('body')->appendAttribute('class', 'mappings browse'); +?> + +pageTitle($translate('Mappings'), 1, $this->translate('CSV Import')); ?> + +trigger('view.browse.before'); ?> + +
+ + + + + + + + + + + + + + + + +
+ +
+ name(); ?> +
    +
  • + hyperlink( + '', + $this->url('admin/csvimport/mapping-id', + [ + 'controller' => 'Mapping', + 'action' => 'show', + 'id' => $model->id() + ] + ), + [ + 'class' => 'o-icon-view', + 'title' => $translate('View'), + ]) + ?> +
  • +
  • + hyperlink( + '', + '#', + [ + 'data-sidebar-content-url' => $this->url('admin/csvimport/mapping-id', + [ + 'controller' => 'Mapping', + 'action' => 'edit', + 'id' => $model->id() + ] + ), + 'class' => 'o-icon-edit sidebar-content', + 'title' => $translate('Edit'), + 'data-sidebar-selector' => '#sidebar', + ] + ); ?> +
  • +
  • + hyperlink( + '', + '#', + [ + 'data-sidebar-content-url' => $this->url('admin/csvimport/mapping-id', + [ + 'controller' => 'Mapping', + 'action' => 'deleteConfirm', + 'id' => $model->id() + ] + ), + 'class' => 'o-icon-delete sidebar-content', + 'title' => $translate('Delete'), + 'data-sidebar-selector' => '#sidebar', + ] + ); ?> +
  • +
+
i18n()->dateFormat($model->created())); ?>
+ +
+ +trigger('view.browse.after'); ?> + + + + + +
+

+
+ + diff --git a/view/csv-import/admin/mapping/edit.phtml b/view/csv-import/admin/mapping/edit.phtml new file mode 100644 index 00000000..627ae1e2 --- /dev/null +++ b/view/csv-import/admin/mapping/edit.phtml @@ -0,0 +1,14 @@ +prepare(); ?> + +pageTitle($this->translate('Edit model'), 3); ?> + +form()->openTag($form); ?> + +formCollection($form); ?> + +
+ +
+ +form()->closeTag($form); ?> + diff --git a/view/csv-import/admin/mapping/select-mapping.phtml b/view/csv-import/admin/mapping/select-mapping.phtml new file mode 100644 index 00000000..2b795502 --- /dev/null +++ b/view/csv-import/admin/mapping/select-mapping.phtml @@ -0,0 +1,16 @@ +prepare(); ?> + +pageTitle($this->translate('Select mapping'), 3); ?> + +form()->openTag($form); ?> + +formCollection($form); ?> + +
+ +
+ +form()->closeTag($form); ?> + diff --git a/view/csv-import/admin/mapping/show.phtml b/view/csv-import/admin/mapping/show.phtml new file mode 100644 index 00000000..962fec38 --- /dev/null +++ b/view/csv-import/admin/mapping/show.phtml @@ -0,0 +1,65 @@ +plugin('escapeHtml'); +$this->htmlElement('body')->appendAttribute('class', 'no-section-hashes'); +$this->headLink()->appendStylesheet($this->assetUrl('css/csvimport.css', 'CSVImport')); +?> + + + + + + + + + + + $column): ?> + + + + + + + +
translate("Column"); ?> translate("Mappings"); ?>translate("Options"); ?>
+ + +
    + + + +
  • > + translate($automaps[$index]['label']); ?> +
  • + + +
  • > + translate($automap['label']); ?> +
  • + + + +
+
+
    +
  • + translate('Data type:'); ?> + +
  • +
  • + translate("Multivalue"); ?> +
  • +
  • + translate("Language:"); ?> + +
  • +
  • + translate("Private values"); ?> +
  • +
  • + translate("Resource identifier property:"); ?> + +
  • +
+
From 11a83f2cdbdde2bfad07d273392aa23995aac798 Mon Sep 17 00:00:00 2001 From: Abel B Date: Mon, 3 Nov 2025 15:41:48 +0100 Subject: [PATCH 07/21] Add JS for AJAX mapping selection when importing. --- asset/js/csvimport.js | 3 ++- asset/js/mappingselect.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 asset/js/mappingselect.js diff --git a/asset/js/csvimport.js b/asset/js/csvimport.js index 86f0ba62..5406f5dd 100644 --- a/asset/js/csvimport.js +++ b/asset/js/csvimport.js @@ -2,8 +2,9 @@ * Initially based on Omeka S omeka2importer.js and resource-core.js. */ (function ($) { + $(document).ready(function () { $(document).trigger('mapping:updated'); }); - $(document).ready(function() { + $(document).on('mapping:updated', function() { /* * Init. */ diff --git a/asset/js/mappingselect.js b/asset/js/mappingselect.js new file mode 100644 index 00000000..966bb166 --- /dev/null +++ b/asset/js/mappingselect.js @@ -0,0 +1,29 @@ +(function ($) { +$(document).ready(function() { + $(document).on('click', '#mapping-select-button', function(e) { + e.preventDefault(); // Stop normal form submission + + var form = $(this).closest('form'); + var formData = form.serialize(); // Collect all form inputs + + $.ajax({ + url: form.attr('action'), + method: 'POST', + data: formData, + success: function(response, status, xhr) { + if (xhr.status === 200 && response.trim().length > 0) { + var newTable = $('
').html(response).find('table'); // parse HTML + var currentTable = $('table'); + + // Replace only the inside of the table + currentTable.html(newTable.html()); + + $(document).trigger('mapping:updated'); + } else { + // alert('Received an empty or invalid response from the server.'); + } + } + }); +}); +}); +})(jQuery) From 5d877549fd0c039790ce4501bca18d40d289d21c Mon Sep 17 00:00:00 2001 From: Abel B Date: Mon, 3 Nov 2025 15:47:01 +0100 Subject: [PATCH 08/21] Add new mapping controllers and routes. --- config/module.config.php | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/config/module.config.php b/config/module.config.php index e67a0e7b..0ba41672 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -24,20 +24,27 @@ ], ], 'form_elements' => [ + 'invokables' => [ + 'CSVImport\Form\MappingEditForm' => Form\MappingEditForm::class, + 'CSVImport\Form\MappingSelectForm' => Form\MappingSelectForm::class, + ], 'factories' => [ 'CSVImport\Form\ImportForm' => Service\Form\ImportFormFactory::class, 'CSVImport\Form\MappingForm' => Service\Form\MappingFormFactory::class, + 'CSVImport\Form\Element\MappingSelect' => Service\Form\Element\MappingSelectFactory::class, ], ], 'controllers' => [ 'factories' => [ 'CSVImport\Controller\Index' => Service\Controller\IndexControllerFactory::class, + 'CSVImport\Controller\Admin\Mapping' => Service\Controller\Admin\MappingControllerFactory::class, ], ], 'controller_plugins' => [ 'factories' => [ 'automapHeadersToMetadata' => Service\ControllerPlugin\AutomapHeadersToMetadataFactory::class, 'findResourcesFromIdentifiers' => Service\ControllerPlugin\FindResourcesFromIdentifiersFactory::class, + 'loadMapping' => Service\ControllerPlugin\LoadMappingFactory::class, ], 'aliases' => [ 'findResourceFromIdentifier' => 'findResourcesFromIdentifiers', @@ -47,6 +54,7 @@ 'invokables' => [ 'csvimport_entities' => Api\Adapter\EntityAdapter::class, 'csvimport_imports' => Api\Adapter\ImportAdapter::class, + 'csvimport_mappings' => Api\Adapter\MappingAdapter::class, ], ], 'service_manager' => [ @@ -92,6 +100,35 @@ ], ], ], + 'mapping' => [ + 'type' => 'Segment', + 'options' => [ + 'route' => '/mapping[/:action]', + 'constraints' => [ + 'action' => '[a-zA-Z][a-zA-Z0-9_-]*', + ], + 'defaults' => [ + '__NAMESPACE__' => 'CSVImport\Controller\Admin', + 'controller' => 'Mapping', + 'action' => 'browse', + ], + ], + ], + 'mapping-id' => [ + 'type' => 'Segment', + 'options' => [ + 'route' => '/mapping/:id[/:action]', + 'constraints' => [ + 'action' => '[a-zA-Z][a-zA-Z0-9_-]*', + 'id' => '\d+', + ], + 'defaults' => [ + '__NAMESPACE__' => 'CSVImport\Controller\Admin', + 'controller' => 'Mapping', + 'action' => 'show', + ], + ], + ], ], ], ], @@ -123,6 +160,10 @@ 'action' => 'past-imports', 'resource' => 'CSVImport\Controller\Index', ], + [ + 'label' => 'Mappings', // @translate + 'route' => 'admin/csvimport/mapping', + ], ], ], ], From cb464f069a7009def4e18c1ea9af75a873708800 Mon Sep 17 00:00:00 2001 From: Abel B Date: Fri, 7 Nov 2025 11:24:17 +0100 Subject: [PATCH 09/21] Add options to save mapping and change menu button to select one. --- src/Controller/IndexController.php | 20 ++++++-------- view/csv-import/index/map.phtml | 42 ++++++++++++++++++------------ 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/Controller/IndexController.php b/src/Controller/IndexController.php index 532bffe2..39c47239 100644 --- a/src/Controller/IndexController.php +++ b/src/Controller/IndexController.php @@ -135,16 +135,7 @@ public function mapAction() $automapOptions['check_names_alone'] = $args['automap_check_names_alone']; $automapOptions['format'] = 'form'; - $autoMaps = []; - if (isset($post['mapping_id'])) { - $this->logger()->debug("Received mapping id."); - $autoMaps = $this->loadMapping($post['mapping_id'], - $columns, - $this->automapHeadersToMetadata($columns, $resourceType, $automapOptions)); - } - if (empty($autoMaps)) { - $autoMaps = $this->automapHeadersToMetadata($columns, $resourceType, $automapOptions); - } + $autoMaps = $this->automapHeadersToMetadata($columns, $resourceType, $automapOptions); $view->setVariable('form', $form); $view->setVariable('resourceType', $resourceType); @@ -172,7 +163,10 @@ public function mapAction() $args = $this->cleanArgs($post); $this->saveUserSettings($args); - $this->saveMapping($args, []); + if (isset($post['save_mapping'])) + { + $this->saveMapping($args, []); + } $dispatcher = $this->jobDispatcher(); $job = $dispatcher->dispatch('CSVImport\Job\Import', $args); // The CsvImport record is created in the job, so it doesn't @@ -485,6 +479,7 @@ protected function saveMapping(array $args): void // We first need to read the file to get the column names // Because we need to remember the column names $filePath = $args['filepath']; + $fileName = $args['filename']; // Check if file exists and is readable if (!file_exists($filePath) || !is_readable($filePath)) { @@ -520,9 +515,10 @@ protected function saveMapping(array $args): void unset($args['media_type']); unset($args['resource_type']); unset($args['automap_check_names_alone']); + unset($args['save_mapping']); $this->logger()->debug(sprintf('[CSV Import: Args to be saved my mapping]' . PHP_EOL . '%s' . PHP_EOL, json_encode($args))); - $this->api()->create('csvimport_mappings', ['mapping' => json_encode($args), 'name' => 'Mapping']); + $this->api()->create('csvimport_mappings', ['mapping' => json_encode($args), 'name' => $fileName]); } } \ No newline at end of file diff --git a/view/csv-import/index/map.phtml b/view/csv-import/index/map.phtml index cc74c884..807618f3 100644 --- a/view/csv-import/index/map.phtml +++ b/view/csv-import/index/map.phtml @@ -40,21 +40,25 @@ $pageTitle = isset($resourceTypeLabels[$resourceType]) formCollection($form); ?>
- hyperlink( - '', - '#', - [ - 'data-sidebar-content-url' => $this->url('admin/csvimport/mapping', - [ - 'controller' => 'Mapping', - 'action' => 'selectMapping', - ] - ), - 'class' => 'button sidebar-content', - 'title' => $this->translate('Select mapping'), - 'data-sidebar-selector' => '#sidebar', - ] - ); ?> +
    +
  • hyperlink( + '', + '#', + [ + 'data-sidebar-content-url' => $this->url('admin/csvimport/mapping', + [ + 'controller' => 'Mapping', + 'action' => 'selectMapping', + ] + ), + 'class' => 'o-icon-menu sidebar-content', + 'title' => $this->translate('Select mapping'), + 'data-sidebar-selector' => '#sidebar', + ] + ); ?> + translate('Load a saved mapping'); ?> +
  • +
@@ -72,7 +76,13 @@ $pageTitle = isset($resourceTypeLabels[$resourceType])
- translate('Batch edit options'); ?> + +
+ + +
partial('common/mapping-table', ['resourceType' => $resourceType, 'columns' => $columns, 'automaps' => $automaps]); ?> From c5a5d0ae3ef078d921d46f7b788e54149e80ec40 Mon Sep 17 00:00:00 2001 From: Abel B Date: Fri, 7 Nov 2025 11:24:42 +0100 Subject: [PATCH 10/21] Fix scripts to take in account newly added table. --- asset/js/csvimport.js | 142 ++++++++++++++++++++------------------ asset/js/mappingselect.js | 8 ++- 2 files changed, 82 insertions(+), 68 deletions(-) diff --git a/asset/js/csvimport.js b/asset/js/csvimport.js index 5406f5dd..c5e5fa92 100644 --- a/asset/js/csvimport.js +++ b/asset/js/csvimport.js @@ -2,9 +2,7 @@ * Initially based on Omeka S omeka2importer.js and resource-core.js. */ (function ($) { - $(document).ready(function () { $(document).trigger('mapping:updated'); }); - - $(document).on('mapping:updated', function() { + $(document).ready(function() { /* * Init. */ @@ -21,6 +19,80 @@ var batchEditCheckboxes = $('.column-select, .select-all'); var batchEditButton = $('#batch-edit-options'); + $(document).on('mapping.updated', newTable); + + newTable(); + + function newTable() { + resetActiveColumns(); + + /* + * Batch edit options. + */ + + $('.batch-edit input[type="checkbox"], .batch-edit .select-all').change(function() { + if ($('.column-select:checked').length > 0) { + batchEditButton.removeClass('inactive').addClass('active sidebar-content'); + } else { + batchEditButton.addClass('inactive').removeClass('active sidebar-content'); + } + }); + + /* + * Sidebar chooser (buttons on each mappable element). + */ + + $('.column-header + .actions a').on('click', function(e) { + console.log("I have been triggered!"); + e.preventDefault(); + if (activeElement !== null) { + activeElement.removeClass('active'); + } + if ($('.column-select:checked').length > 0) { + resetActiveColumns(); + } + activeElement = $(e.target).closest('tr.mappable'); + activeElement.addClass('active'); + + var actionElement = $(this); + $('.sidebar-chooser li').removeClass('active'); + actionElement.parent().addClass('active'); + var target = actionElement.data('sidebar-selector'); + + var sidebar = $(target); + if (!sidebar.hasClass('active') ) { + defaultSidebarHtml = sidebar.html(); + } + var columnName = activeElement.data('column'); + if (sidebar.find('.column-name').length > 0) { + $('.column-name').text(columnName); + } else { + sidebar.find('h3').append(' ' + columnName + ''); + } + + var currentSidebar = $('.sidebar.active'); + if (currentSidebar.attr('id') != target) { + currentSidebar.removeClass('active'); + sidebar.html(defaultSidebarHtml); + rebindInputs(sidebar); + } + + Omeka.openSidebar(sidebar); + populateSidebar(); + }); + + /* + * Actions on mapped columns. + */ + + // Remove mapping. + $('.section').on('click', 'a.remove-mapping', function(e) { + e.preventDefault(); + e.stopPropagation(); + $(this).parents('li.mapping').remove(); + }); + }; + /* * Rebinding chosen selects and property selector after sidebar hydration. */ @@ -61,47 +133,6 @@ }); } - /* - * Sidebar chooser (buttons on each mappable element). - */ - - $('.column-header + .actions a').on('click', function(e) { - e.preventDefault(); - if (activeElement !== null) { - activeElement.removeClass('active'); - } - if ($('.column-select:checked').length > 0) { - resetActiveColumns(); - } - activeElement = $(e.target).closest('tr.mappable'); - activeElement.addClass('active'); - - var actionElement = $(this); - $('.sidebar-chooser li').removeClass('active'); - actionElement.parent().addClass('active'); - var target = actionElement.data('sidebar-selector'); - - var sidebar = $(target); - if (!sidebar.hasClass('active') ) { - defaultSidebarHtml = sidebar.html(); - } - var columnName = activeElement.data('column'); - if (sidebar.find('.column-name').length > 0) { - $('.column-name').text(columnName); - } else { - sidebar.find('h3').append(' ' + columnName + ''); - } - - var currentSidebar = $('.sidebar.active'); - if (currentSidebar.attr('id') != target) { - currentSidebar.removeClass('active'); - sidebar.html(defaultSidebarHtml); - rebindInputs(sidebar); - } - - Omeka.openSidebar(sidebar); - populateSidebar(); - }); function populateSidebar() { $('.active.element .options :input:not(:disabled)').each(function() { @@ -120,17 +151,6 @@ }); } - /* - * Batch edit options. - */ - - $('.batch-edit input[type="checkbox"], .batch-edit .select-all').change(function() { - if ($('.column-select:checked').length > 0) { - batchEditButton.removeClass('inactive').addClass('active sidebar-content'); - } else { - batchEditButton.addClass('inactive').removeClass('active sidebar-content'); - } - }); $(document).on('click', '#batch-edit-options.active', function() { defaultSidebarHtml = $('#column-options').html(); @@ -285,6 +305,7 @@ }); $(document).on('click', '#column-options .confirm-panel button', function() { + console.log('clicked!'); var sidebar = $(this).parents('.sidebar'); var languageTextInput = $('#value-language'); var languageValue = languageTextInput.val(); @@ -342,17 +363,6 @@ batchEditButton.removeClass('active sidebar-content').addClass('inactive'); } - /* - * Actions on mapped columns. - */ - - // Remove mapping. - $('.section').on('click', 'a.remove-mapping', function(e) { - e.preventDefault(); - e.stopPropagation(); - $(this).parents('li.mapping').remove(); - }); - function applyMappings(flagName, flagValue, flagLiClass, flagLabel) { var hasFlag = activeElement.find('ul.mappings li.' + flagLiClass); if (flagValue == 'default') { diff --git a/asset/js/mappingselect.js b/asset/js/mappingselect.js index 966bb166..59acfad9 100644 --- a/asset/js/mappingselect.js +++ b/asset/js/mappingselect.js @@ -6,6 +6,9 @@ $(document).ready(function() { var form = $(this).closest('form'); var formData = form.serialize(); // Collect all form inputs + var sidebar = $(this).parents('.sidebar'); + Omeka.closeSidebar(sidebar); + $.ajax({ url: form.attr('action'), method: 'POST', @@ -16,9 +19,10 @@ $(document).ready(function() { var currentTable = $('table'); // Replace only the inside of the table - currentTable.html(newTable.html()); + currentTable.replaceWith(newTable); - $(document).trigger('mapping:updated'); + $(document).trigger("enhance.tablesaw"); + $(document).trigger('mapping.updated'); } else { // alert('Received an empty or invalid response from the server.'); } From 25ba1d96c35b14efe570450c54d1f240c551aaa3 Mon Sep 17 00:00:00 2001 From: Abel B Date: Fri, 14 Nov 2025 09:54:29 +0100 Subject: [PATCH 11/21] Bump back to v2.6.0 (will be bumped again on main). --- config/module.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/module.ini b/config/module.ini index 781ee70f..4a035b55 100644 --- a/config/module.ini +++ b/config/module.ini @@ -8,5 +8,5 @@ author_link = "https://omeka.org/" module_link = "https://omeka.org/s/docs/user-manual/modules/csvimport/" support_link = "https://forum.omeka.org/c/omeka-s/modules" configurable = false -version = "2.7.0" +version = "2.6.2" omeka_version_constraint = "^4.0.0" From ec581ee14950c9217aa24eb18c827d123ceea69f Mon Sep 17 00:00:00 2001 From: Abel B Date: Fri, 14 Nov 2025 09:55:00 +0100 Subject: [PATCH 12/21] Clean code with gulp fix:module:cs. --- src/Controller/Admin/MappingController.php | 12 +++++------- src/Controller/IndexController.php | 7 ++----- src/Entity/CSVImportMapping.php | 2 +- src/Form/MappingSelectForm.php | 5 +---- src/Job/Import.php | 2 +- src/Mapping/AbstractResourceMapping.php | 2 +- src/Mapping/MediaSourceMapping.php | 2 +- src/Mapping/PropertyMapping.php | 8 ++++---- src/Mvc/Controller/Plugin/LoadMapping.php | 14 ++++++-------- 9 files changed, 22 insertions(+), 32 deletions(-) diff --git a/src/Controller/Admin/MappingController.php b/src/Controller/Admin/MappingController.php index dbf01a16..f64d8ce8 100644 --- a/src/Controller/Admin/MappingController.php +++ b/src/Controller/Admin/MappingController.php @@ -4,7 +4,6 @@ use Laminas\Mvc\Controller\AbstractActionController; use Laminas\View\Model\ViewModel; -use Omeka\Stdlib\Message; use Omeka\Form\ConfirmForm; use CSVImport\Form\MappingEditForm; use CSVImport\Form\MappingSelectForm; @@ -15,7 +14,7 @@ public function browseAction() { $this->setBrowseDefaults('created'); $response = $this->api()->search('csvimport_mappings'); - + $this->paginator($response->getTotalResults()); $formDeleteSelected = $this->getForm(ConfirmForm::class); @@ -43,13 +42,13 @@ public function showAction() $view = new ViewModel; $view->setVariable('propertiesMap', $propertiesMap); $view->setVariable('columns', $mappingModel['columns']); - unset( $mappingModel['columns']); + unset($mappingModel['columns']); $this->logger()->debug(json_encode($mappingModel)); $view->setVariable('automaps', $mappingModel); return $view; } - /* + /* * meant for JS */ public function selectMappingAction() @@ -78,13 +77,12 @@ public function selectMappingAction() $view = new ViewModel([ 'automaps' => $this->loadMapping($mappingId, $columns, []), 'columns' => $columns, - 'resourceType' => $session->resourceType + 'resourceType' => $session->resourceType, ]); $view->setTemplate('common/mapping-table'); $view->setTerminal(true); // no layout return $view; - } - else { + } else { return $this->getResponse()->setStatusCode(404)->setContent('Mapping not found.'); // @translate } } diff --git a/src/Controller/IndexController.php b/src/Controller/IndexController.php index 39c47239..b4d7986b 100644 --- a/src/Controller/IndexController.php +++ b/src/Controller/IndexController.php @@ -150,7 +150,6 @@ public function mapAction() $view->setVariable('dataTypes', $this->getDataTypes()); return $view; - } else { $form = $this->getForm(MappingForm::class, $mappingOptions); $form->setData($post); @@ -163,8 +162,7 @@ public function mapAction() $args = $this->cleanArgs($post); $this->saveUserSettings($args); - if (isset($post['save_mapping'])) - { + if (isset($post['save_mapping'])) { $this->saveMapping($args, []); } $dispatcher = $this->jobDispatcher(); @@ -472,7 +470,6 @@ protected function saveUserSettings(array $settings) /** * Save mapping. - * */ protected function saveMapping(array $args): void { @@ -521,4 +518,4 @@ protected function saveMapping(array $args): void $this->api()->create('csvimport_mappings', ['mapping' => json_encode($args), 'name' => $fileName]); } -} \ No newline at end of file +} diff --git a/src/Entity/CSVImportMapping.php b/src/Entity/CSVImportMapping.php index 9ba5f65b..25c0cc39 100644 --- a/src/Entity/CSVImportMapping.php +++ b/src/Entity/CSVImportMapping.php @@ -76,4 +76,4 @@ public function prePersist(LifecycleEventArgs $eventArgs) { $this->created = new DateTime('now'); } -} \ No newline at end of file +} diff --git a/src/Form/MappingSelectForm.php b/src/Form/MappingSelectForm.php index 8a78ed95..a7d1ef87 100644 --- a/src/Form/MappingSelectForm.php +++ b/src/Form/MappingSelectForm.php @@ -2,13 +2,10 @@ namespace CSVImport\Form; use CSVImport\Form\Element\MappingSelect; -use Omeka\Form\Element\ItemSetSelect; use Laminas\Form\Form; -use Laminas\Form\Element\Hidden; class MappingSelectForm extends Form { - public function init() { $this->setAttribute('action', '/admin/csvimport/mapping/selectMapping'); @@ -31,4 +28,4 @@ public function init() ], ]); } -} \ No newline at end of file +} diff --git a/src/Job/Import.php b/src/Job/Import.php index 614b13ae..a8d68e33 100644 --- a/src/Job/Import.php +++ b/src/Job/Import.php @@ -504,7 +504,7 @@ protected function checkMedias(array $data) $this->hasErr = true; $this->logger->err(new Message('A media to create is not attached to an item (%s).', // @translate empty($entityJson['o:source']) - ? (isset($entityJson['o:ingester']) ? $entityJson['o:ingester'] : 'unknown ingester') // @translate + ? ($entityJson['o:ingester'] ?? 'unknown ingester') // @translate : $entityJson['o:ingester'] . ': ' . $entityJson['o:source'])); } } diff --git a/src/Mapping/AbstractResourceMapping.php b/src/Mapping/AbstractResourceMapping.php index b86bc92a..45d98cd3 100644 --- a/src/Mapping/AbstractResourceMapping.php +++ b/src/Mapping/AbstractResourceMapping.php @@ -49,7 +49,7 @@ public function processRow(array $row) // First, pull in the global settings. $this->processGlobalArgs(); - $multivalueMap = isset($this->args['column-multivalue']) ? $this->args['column-multivalue'] : []; + $multivalueMap = $this->args['column-multivalue'] ?? []; $multivalueSeparator = $this->args['multivalue_separator']; foreach ($row as $index => $values) { if (empty($multivalueMap[$index])) { diff --git a/src/Mapping/MediaSourceMapping.php b/src/Mapping/MediaSourceMapping.php index 5a43e9fa..475d0d49 100644 --- a/src/Mapping/MediaSourceMapping.php +++ b/src/Mapping/MediaSourceMapping.php @@ -51,7 +51,7 @@ public function processRow(array $row) $mediaAdapters = $config['media_ingester_adapter']; $action = $this->args['action']; - $multivalueMap = isset($this->args['column-multivalue']) ? $this->args['column-multivalue'] : []; + $multivalueMap = $this->args['column-multivalue'] ?? []; $multivalueSeparator = $this->args['multivalue_separator']; foreach ($row as $index => $values) { if (isset($mediaMap[$index])) { diff --git a/src/Mapping/PropertyMapping.php b/src/Mapping/PropertyMapping.php index cf866be5..e1a6725b 100644 --- a/src/Mapping/PropertyMapping.php +++ b/src/Mapping/PropertyMapping.php @@ -58,12 +58,12 @@ public function processRow(array $row) $dataTypeAdapters = $this->getDataTypeAdapters(); // Get default option values. - $globalLanguage = isset($this->args['global_language']) ? $this->args['global_language'] : ''; + $globalLanguage = $this->args['global_language'] ?? ''; - $multivalueMap = isset($this->args['column-multivalue']) ? $this->args['column-multivalue'] : []; + $multivalueMap = $this->args['column-multivalue'] ?? []; $multivalueSeparator = $this->args['multivalue_separator']; - $resourceIdentifierPropertyMap = isset($this->args['column-resource-identifier-property']) ? $this->args['column-resource-identifier-property'] : []; + $resourceIdentifierPropertyMap = $this->args['column-resource-identifier-property'] ?? []; $findResourceFromIdentifier = $this->findResourceFromIdentifier; foreach ($row as $index => $values) { @@ -106,7 +106,7 @@ public function processRow(array $row) // Check if a label is provided after the url. // Note: A url has no space, but a uri may have. if (strpos($value, ' ')) { - list($valueId, $valueLabel) = explode(' ', $value, 2); + [$valueId, $valueLabel] = explode(' ', $value, 2); $valueLabel = trim($valueLabel); } else { $valueId = $value; diff --git a/src/Mvc/Controller/Plugin/LoadMapping.php b/src/Mvc/Controller/Plugin/LoadMapping.php index b3d2404e..4a05b38f 100644 --- a/src/Mvc/Controller/Plugin/LoadMapping.php +++ b/src/Mvc/Controller/Plugin/LoadMapping.php @@ -81,8 +81,8 @@ public function __invoke(int $id, array $columns, array $defaultAutomap) $originalColumns = $mappingValue['columns']; unset($mappingValue['columns']); // so we don't iterate over it after like it's an actual mapping - // $this->logger->debug(sprintf('Old columns : ' . PHP_EOL . '%s' . PHP_EOL . 'New columns:' . PHP_EOL . '%s' . PHP_EOL, - // json_encode($originalColumns), json_encode($columns))); + // $this->logger->debug(sprintf('Old columns : ' . PHP_EOL . '%s' . PHP_EOL . 'New columns:' . PHP_EOL . '%s' . PHP_EOL, + // json_encode($originalColumns), json_encode($columns))); // Find the mapping between old column indexes and current columns, according to name matching $oldToNewColumn = []; @@ -94,8 +94,7 @@ public function __invoke(int $id, array $columns, array $defaultAutomap) $oldToNewColumn[strval($columnMapping)] = $index; } } - } - else { + } else { foreach ($originalColumns as $index => $column) { $oldToNewColumn[strval($index)] = $index; } @@ -115,7 +114,7 @@ public function __invoke(int $id, array $columns, array $defaultAutomap) /* * Reading each entry that was sent by the user in the form * The structure is complicated and undocumented. - */ + */ foreach ($mappingValue as $mappingValueColumnName => $mappingValueColumn) { $name = ""; if (str_contains($mappingValueColumnName, 'column-')) { @@ -133,14 +132,14 @@ public function __invoke(int $id, array $columns, array $defaultAutomap) $element["special"] = " data-property-id=\"" . $subproperty . "\""; $element["label"] = explode(':', $subindex)[1] ?? $subindex; $element["value"] = $subproperty; - $automap[$oldToNewColumn[$index]][] = $element; + $automap[$oldToNewColumn[$index]][] = $element; } } } } // these are column options. Only one per column, for data simplicity we put it in $automap[ColumnIndex][0] - else if ($name == "data-type" + elseif ($name == "data-type" || $name == "multivalue" || $name == "language" || $name == "private-values" @@ -168,7 +167,6 @@ public function __invoke(int $id, array $columns, array $defaultAutomap) } } } - } // default automap may be empty From ddb08fc63fb14b407074c7b69573c4f86851fd9a Mon Sep 17 00:00:00 2001 From: Abel B Date: Fri, 14 Nov 2025 10:16:19 +0100 Subject: [PATCH 13/21] Bump again to 3.0.0. --- config/module.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/module.ini b/config/module.ini index 4a035b55..29922adc 100644 --- a/config/module.ini +++ b/config/module.ini @@ -8,5 +8,5 @@ author_link = "https://omeka.org/" module_link = "https://omeka.org/s/docs/user-manual/modules/csvimport/" support_link = "https://forum.omeka.org/c/omeka-s/modules" configurable = false -version = "2.6.2" +version = "3.0.0" omeka_version_constraint = "^4.0.0" From 02543eaa1cf2ff3dc19407104ecf86603993d977 Mon Sep 17 00:00:00 2001 From: Abel B Date: Fri, 14 Nov 2025 13:50:20 +0100 Subject: [PATCH 14/21] Remove useless comments and console logs used for debug. --- asset/js/csvimport.js | 2 -- asset/js/mappingselect.js | 2 +- src/Controller/Admin/MappingController.php | 5 ++--- src/Mvc/Controller/Plugin/LoadMapping.php | 15 ++------------- 4 files changed, 5 insertions(+), 19 deletions(-) diff --git a/asset/js/csvimport.js b/asset/js/csvimport.js index c5e5fa92..0b2395cf 100644 --- a/asset/js/csvimport.js +++ b/asset/js/csvimport.js @@ -43,7 +43,6 @@ */ $('.column-header + .actions a').on('click', function(e) { - console.log("I have been triggered!"); e.preventDefault(); if (activeElement !== null) { activeElement.removeClass('active'); @@ -305,7 +304,6 @@ }); $(document).on('click', '#column-options .confirm-panel button', function() { - console.log('clicked!'); var sidebar = $(this).parents('.sidebar'); var languageTextInput = $('#value-language'); var languageValue = languageTextInput.val(); diff --git a/asset/js/mappingselect.js b/asset/js/mappingselect.js index 59acfad9..916a6ffa 100644 --- a/asset/js/mappingselect.js +++ b/asset/js/mappingselect.js @@ -24,7 +24,7 @@ $(document).ready(function() { $(document).trigger("enhance.tablesaw"); $(document).trigger('mapping.updated'); } else { - // alert('Received an empty or invalid response from the server.'); + console.error('Received an empty or invalid response from the server.'); } } }); diff --git a/src/Controller/Admin/MappingController.php b/src/Controller/Admin/MappingController.php index f64d8ce8..4c5b2e2f 100644 --- a/src/Controller/Admin/MappingController.php +++ b/src/Controller/Admin/MappingController.php @@ -37,7 +37,7 @@ public function showAction() $propertiesMap[$property->id()] = $property->term(); } - $mappingModel = $this->loadMapping($this->params('id'), [], []); + $mappingModel = $this->loadMapping($this->params('id'), []); $view = new ViewModel; $view->setVariable('propertiesMap', $propertiesMap); @@ -75,7 +75,7 @@ public function selectMappingAction() $response = $this->api()->read('csvimport_mappings', $mappingId); if ($response) { $view = new ViewModel([ - 'automaps' => $this->loadMapping($mappingId, $columns, []), + 'automaps' => $this->loadMapping($mappingId, $columns), 'columns' => $columns, 'resourceType' => $session->resourceType, ]); @@ -145,7 +145,6 @@ public function deleteConfirmAction() $view->setTerminal(true); $view->setTemplate('common/delete-confirm-details'); $view->setVariable('resource', $mappingModel); - // $view->setVariable('partialPath', '...') $view->setVariable('resourceLabel', 'Mapping'); // @translate return $view; } diff --git a/src/Mvc/Controller/Plugin/LoadMapping.php b/src/Mvc/Controller/Plugin/LoadMapping.php index 4a05b38f..9392327c 100644 --- a/src/Mvc/Controller/Plugin/LoadMapping.php +++ b/src/Mvc/Controller/Plugin/LoadMapping.php @@ -1,7 +1,7 @@ api->read('csvimport_mappings', $id)->getContent(); @@ -169,17 +169,6 @@ public function __invoke(int $id, array $columns, array $defaultAutomap) } } - // default automap may be empty - /* - foreach ($defaultAutomap as $index => $property) { - if (!array_key_exists($index, $automap)) { - $automap[$index][] = $property; - } - } - */ - - // $this->logger->debug(sprintf("[Mapping loaded]" . PHP_EOL . "%s" . PHP_EOL, json_encode($automap))); - return $automap; } } From 7c92dce19109362326c5ed709456b2989d15be02 Mon Sep 17 00:00:00 2001 From: Abel B Date: Fri, 14 Nov 2025 13:54:03 +0100 Subject: [PATCH 15/21] Fix SQL update for 3.0.0 and indent lines. --- Module.php | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/Module.php b/Module.php index c5764f58..80d2db81 100644 --- a/Module.php +++ b/Module.php @@ -21,9 +21,33 @@ public function install(ServiceLocatorInterface $serviceLocator) { $connection = $serviceLocator->get('Omeka\Connection'); $sql = <<<'SQL' -CREATE TABLE csvimport_mapping (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, created DATETIME NOT NULL, mapping LONGTEXT NOT NULL COMMENT '(DC2Type:json)', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; -CREATE TABLE csvimport_import (id INT AUTO_INCREMENT NOT NULL, job_id INT NOT NULL, undo_job_id INT DEFAULT NULL, comment VARCHAR(255) DEFAULT NULL, resource_type VARCHAR(255) NOT NULL, has_err TINYINT(1) NOT NULL, stats LONGTEXT NOT NULL COMMENT '(DC2Type:json_array)', UNIQUE INDEX UNIQ_17B50881BE04EA9 (job_id), UNIQUE INDEX UNIQ_17B508814C276F75 (undo_job_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; -CREATE TABLE csvimport_entity (id INT AUTO_INCREMENT NOT NULL, job_id INT NOT NULL, entity_id INT NOT NULL, resource_type VARCHAR(255) NOT NULL, INDEX IDX_84D382F4BE04EA9 (job_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; +CREATE TABLE csvimport_mapping ( + id INT AUTO_INCREMENT NOT NULL, + name VARCHAR(255) NOT NULL, + created DATETIME NOT NULL, + mapping LONGTEXT NOT NULL COMMENT '(DC2Type:json)', + PRIMARY KEY(id)) +DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; +CREATE TABLE csvimport_import ( + id INT AUTO_INCREMENT NOT NULL, + job_id INT NOT NULL, + undo_job_id INT DEFAULT NULL, + comment VARCHAR(255) DEFAULT NULL, + resource_type VARCHAR(255) NOT NULL, + has_err TINYINT(1) NOT NULL, + stats LONGTEXT NOT NULL COMMENT '(DC2Type:json_array)', + UNIQUE INDEX UNIQ_17B50881BE04EA9 (job_id), + UNIQUE INDEX UNIQ_17B508814C276F75 (undo_job_id), + PRIMARY KEY(id)) +DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; +CREATE TABLE csvimport_entity ( + id INT AUTO_INCREMENT NOT NULL, + job_id INT NOT NULL, + entity_id INT NOT NULL, + resource_type VARCHAR(255) NOT NULL, + INDEX IDX_84D382F4BE04EA9 (job_id), + PRIMARY KEY(id)) +DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; ALTER TABLE csvimport_import ADD CONSTRAINT FK_17B50881BE04EA9 FOREIGN KEY (job_id) REFERENCES job (id); ALTER TABLE csvimport_import ADD CONSTRAINT FK_17B508814C276F75 FOREIGN KEY (undo_job_id) REFERENCES job (id); ALTER TABLE csvimport_entity ADD CONSTRAINT FK_84D382F4BE04EA9 FOREIGN KEY (job_id) REFERENCES job (id); @@ -70,7 +94,13 @@ public function upgrade($oldVersion, $newVersion, ServiceLocatorInterface $servi if (version_compare($oldVersion, '2.7.0', '<')) { $connection = $serviceLocator->get('Omeka\Connection'); $sql = <<<'SQL' -CREATE TABLE csvimport_entity (id INT AUTO_INCREMENT NOT NULL, job_id INT NOT NULL, entity_id INT NOT NULL, resource_type VARCHAR(255) NOT NULL, INDEX IDX_84D382F4BE04EA9 (job_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; +CREATE TABLE csvimport_mapping ( + id INT AUTO_INCREMENT NOT NULL, + name VARCHAR(255) NOT NULL, + created DATETIME NOT NULL, + mapping LONGTEXT NOT NULL COMMENT '(DC2Type:json)', + RIMARY KEY(id)) +DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; SQL; $sqls = array_filter(array_map('trim', explode(';', $sql))); foreach ($sqls as $sql) { From 4a9fbd4be1747b2e9623019c97028ddad26137de Mon Sep 17 00:00:00 2001 From: Abel B Date: Fri, 14 Nov 2025 13:58:48 +0100 Subject: [PATCH 16/21] Add 'P' to 'RIMARY KEY'. --- Module.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Module.php b/Module.php index 80d2db81..a8bb1518 100644 --- a/Module.php +++ b/Module.php @@ -99,7 +99,7 @@ public function upgrade($oldVersion, $newVersion, ServiceLocatorInterface $servi name VARCHAR(255) NOT NULL, created DATETIME NOT NULL, mapping LONGTEXT NOT NULL COMMENT '(DC2Type:json)', - RIMARY KEY(id)) + PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; SQL; $sqls = array_filter(array_map('trim', explode(';', $sql))); From fecbb15167d4c75afbfb7d566a7866d68a0fcd8b Mon Sep 17 00:00:00 2001 From: Abel B Date: Wed, 19 Nov 2025 09:45:14 +0100 Subject: [PATCH 17/21] Add unique constraint on mapping name. --- Module.php | 6 ++++-- src/Api/Adapter/MappingAdapter.php | 11 +++++++++++ src/Entity/CSVImportMapping.php | 8 ++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Module.php b/Module.php index a8bb1518..72111155 100644 --- a/Module.php +++ b/Module.php @@ -26,7 +26,8 @@ public function install(ServiceLocatorInterface $serviceLocator) name VARCHAR(255) NOT NULL, created DATETIME NOT NULL, mapping LONGTEXT NOT NULL COMMENT '(DC2Type:json)', - PRIMARY KEY(id)) + PRIMARY KEY(id), + UNIQUE INDEX UNIQ_B0D508235E237E06 (name)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; CREATE TABLE csvimport_import ( id INT AUTO_INCREMENT NOT NULL, @@ -99,7 +100,8 @@ public function upgrade($oldVersion, $newVersion, ServiceLocatorInterface $servi name VARCHAR(255) NOT NULL, created DATETIME NOT NULL, mapping LONGTEXT NOT NULL COMMENT '(DC2Type:json)', - PRIMARY KEY(id)) + PRIMARY KEY(id), + UNIQUE INDEX UNIQ_B0D508235E237E06 (name)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB; SQL; $sqls = array_filter(array_map('trim', explode(';', $sql))); diff --git a/src/Api/Adapter/MappingAdapter.php b/src/Api/Adapter/MappingAdapter.php index 475d9175..58df9ca2 100644 --- a/src/Api/Adapter/MappingAdapter.php +++ b/src/Api/Adapter/MappingAdapter.php @@ -6,6 +6,7 @@ use Omeka\Entity\EntityInterface; use Omeka\Stdlib\ErrorStore; use CSVImport\Entity\CSVImportMapping; +use Doctrine\ORM\QueryBuilder; class MappingAdapter extends AbstractEntityAdapter { @@ -48,4 +49,14 @@ public function validateEntity(EntityInterface $entity, ErrorStore $errorStore) $errorStore->addError('o-module-csvimport-mapping:mapping', 'Mapping must exists.'); // @translate } } + + public function buildQuery(QueryBuilder $qb, array $query) + { + if (isset($query['name'])) { + $qb->andWhere($qb->expr()->eq( + 'omeka_root.name', + $this->createNamedParameter($qb, $query['name'])) + ); + } + } } diff --git a/src/Entity/CSVImportMapping.php b/src/Entity/CSVImportMapping.php index 25c0cc39..749b5a02 100644 --- a/src/Entity/CSVImportMapping.php +++ b/src/Entity/CSVImportMapping.php @@ -8,6 +8,14 @@ /** * @Entity * @HasLifecycleCallbacks + * + * @Table( + * uniqueConstraints={ + * @UniqueConstraint( + * columns={"name"} + * ) + * } + * ) */ class CSVImportMapping extends AbstractEntity { From 57a99b2f1a0c3ed99cd12be2fff111266cd348ad Mon Sep 17 00:00:00 2001 From: Abel B Date: Wed, 19 Nov 2025 09:47:20 +0100 Subject: [PATCH 18/21] Move saveMapping() to PluginController and add a SaveMapping form for sidebar. --- config/module.config.php | 2 + src/Form/MappingSaveForm.php | 41 +++++ src/Mvc/Controller/Plugin/SaveMapping.php | 146 ++++++++++++++++++ .../ControllerPlugin/SaveMappingFactory.php | 18 +++ src/Service/Form/MappingSaveFormFactory.php | 21 +++ 5 files changed, 228 insertions(+) create mode 100644 src/Form/MappingSaveForm.php create mode 100644 src/Mvc/Controller/Plugin/SaveMapping.php create mode 100644 src/Service/ControllerPlugin/SaveMappingFactory.php create mode 100644 src/Service/Form/MappingSaveFormFactory.php diff --git a/config/module.config.php b/config/module.config.php index 0ba41672..bcc84ba7 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -32,6 +32,7 @@ 'CSVImport\Form\ImportForm' => Service\Form\ImportFormFactory::class, 'CSVImport\Form\MappingForm' => Service\Form\MappingFormFactory::class, 'CSVImport\Form\Element\MappingSelect' => Service\Form\Element\MappingSelectFactory::class, + 'CSVImport\Form\MappingSaveForm' => Service\Form\MappingSaveFormFactory::class, ], ], 'controllers' => [ @@ -45,6 +46,7 @@ 'automapHeadersToMetadata' => Service\ControllerPlugin\AutomapHeadersToMetadataFactory::class, 'findResourcesFromIdentifiers' => Service\ControllerPlugin\FindResourcesFromIdentifiersFactory::class, 'loadMapping' => Service\ControllerPlugin\LoadMappingFactory::class, + 'saveMapping' => Service\ControllerPlugin\SaveMappingFactory::class, ], 'aliases' => [ 'findResourceFromIdentifier' => 'findResourcesFromIdentifiers', diff --git a/src/Form/MappingSaveForm.php b/src/Form/MappingSaveForm.php new file mode 100644 index 00000000..59f093ba --- /dev/null +++ b/src/Form/MappingSaveForm.php @@ -0,0 +1,41 @@ +setAttribute('action', 'mapping/save'); + + $this->add([ + 'name'=> 'job_id', + 'type'=> 'hidden', + 'attributes' => [ + 'value' => $this->getOption('job_id'), + ] + ]); + + $this->add([ + 'name' => 'mapping_name', + 'type' => 'text', + 'options' => [ + 'label' => 'Mapping name', //@translate + ], + 'attributes' => [ + 'required' => true, + ], + ]); + $this->add([ + 'name' => 'override_mapping', + 'type' => Checkbox::class, + 'options' => [ + 'label' => 'Override mapping if it already exists?', //@translate + ], + ]); + } +} diff --git a/src/Mvc/Controller/Plugin/SaveMapping.php b/src/Mvc/Controller/Plugin/SaveMapping.php new file mode 100644 index 00000000..72e26c23 --- /dev/null +++ b/src/Mvc/Controller/Plugin/SaveMapping.php @@ -0,0 +1,146 @@ +connection = $connection; + $this->api = $apiManager; + $this->logger = $logger; + } + + /** + * Save mapping. + */ + public function __invoke(array $args): bool + { + $shouldOverrideMapping = false; + $mappingName = $args['mapping_name']; + + $this->logger->debug('[CSVImport] Mapping name.'); + $this->logger->debug(json_encode($mappingName)); + + $alreadyExistsContent = $this->api->search('csvimport_mappings', ['name' => $mappingName])->getContent(); + if (count($alreadyExistsContent) > 0) { + if (!empty($args['override_mapping'])) + { + $shouldOverrideMapping = true; + } + else + { + $this->logger->debug('[CSVImport] Already existing mapping.'); + $this->logger->debug(json_encode($alreadyExistsContent)); + return false; + } + } + + if (empty($args['columns'])) { + // We first need to read the file to get the column names + // Because we need to remember the column names + $filePath = $args['filepath']; + $fileName = $args['filename']; + + // Check if file exists and is readable + if (!file_exists($filePath) || !is_readable($filePath)) { + $this->logger->err(sprintf("[CSV Import]: File '%s' not found when saving mapping.", $filePath)); // @translate + } + + // Open the file for reading + if (($handle = fopen($filePath, 'r')) !== false) { + // Read the first line as CSV (header row) + $args['columns'] = fgetcsv($handle); + + // Close file + fclose($handle); + + // Output the column names + if (!$args['columns']) { + $this->logger->err(sprintf("[CSV Import]: Unable to read columns when saving mapping.")); // @translate + } + } else { + $this->logger->err(sprintf("[CSV Import]: File '%s' could not be opened when saving mapping.", $filePath)); // @translate + } + + if (empty($args['columns'])) { + $this->logger->err(sprintf("[CSV Import]: Unable to get columns from file '%s'.", $filePath)); // @translate + } + } + + $this->logger->debug(sprintf("[CSV Import] Column names: " . PHP_EOL . "%s" . PHP_EOL, json_encode($args["columns"]))); + + // don't save irrelevant data + unset($args['filename']); + unset($args['filesize']); + unset($args['filepath']); + unset($args['media_type']); + unset($args['resource_type']); + unset($args['automap_check_names_alone']); + unset($args['mapping_name']); + unset($args['override_mapping']); + + $this->logger->debug(sprintf('[CSV Import: Args to be saved my mapping]' . PHP_EOL . '%s' . PHP_EOL, json_encode($args))); + + if ($shouldOverrideMapping) { + $this->api->update('csvimport_mappings', ['name' => $mappingName], ['mapping' => json_encode($args)], [], ['isPartial' => true]); + } + else { + $this->api->create('csvimport_mappings', ['mapping' => json_encode($args), 'name' => $mappingName]); + } + + return true; + } +} diff --git a/src/Service/ControllerPlugin/SaveMappingFactory.php b/src/Service/ControllerPlugin/SaveMappingFactory.php new file mode 100644 index 00000000..eefba16c --- /dev/null +++ b/src/Service/ControllerPlugin/SaveMappingFactory.php @@ -0,0 +1,18 @@ +get('Omeka\Connection'), + $services->get('Omeka\ApiManager'), + $services->get('Omeka\Logger') + ); + } +} diff --git a/src/Service/Form/MappingSaveFormFactory.php b/src/Service/Form/MappingSaveFormFactory.php new file mode 100644 index 00000000..fc4b6bfd --- /dev/null +++ b/src/Service/Form/MappingSaveFormFactory.php @@ -0,0 +1,21 @@ +setOption("job_id", $options["job_id"]); + return $form; + } +} From 763318c04725cca2b9d6bf18276742f412e27b11 Mon Sep 17 00:00:00 2001 From: Abel B Date: Wed, 19 Nov 2025 09:47:55 +0100 Subject: [PATCH 19/21] Create Save mapping sidebar view. --- .../admin/mapping/save-mapping.phtml | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 view/csv-import/admin/mapping/save-mapping.phtml diff --git a/view/csv-import/admin/mapping/save-mapping.phtml b/view/csv-import/admin/mapping/save-mapping.phtml new file mode 100644 index 00000000..77074497 --- /dev/null +++ b/view/csv-import/admin/mapping/save-mapping.phtml @@ -0,0 +1,43 @@ +prepare(); ?> + +pageTitle($this->translate('Save mapping'), 3); ?> + +form()->openTag($form); ?> + +formCollection($form); ?> + +
+ +
+ +form()->closeTag($form); ?> + + \ No newline at end of file From 6b623639a43285c0ab07e6a8e7ff1ca5e8d2b61f Mon Sep 17 00:00:00 2001 From: Abel B Date: Wed, 19 Nov 2025 09:48:54 +0100 Subject: [PATCH 20/21] Move save of mapping in past imports table. --- src/Controller/Admin/MappingController.php | 71 ++++++++++++++++++++++ src/Controller/IndexController.php | 57 +---------------- view/csv-import/admin/mapping/edit.phtml | 2 +- view/csv-import/index/map.phtml | 42 ++++++------- view/csv-import/index/past-imports.phtml | 35 +++++++++++ 5 files changed, 130 insertions(+), 77 deletions(-) diff --git a/src/Controller/Admin/MappingController.php b/src/Controller/Admin/MappingController.php index 4c5b2e2f..1912f5db 100644 --- a/src/Controller/Admin/MappingController.php +++ b/src/Controller/Admin/MappingController.php @@ -7,6 +7,7 @@ use Omeka\Form\ConfirmForm; use CSVImport\Form\MappingEditForm; use CSVImport\Form\MappingSelectForm; +use CSVImport\Form\MappingSaveForm; class MappingController extends AbstractActionController { @@ -48,6 +49,76 @@ public function showAction() return $view; } + public function saveAction() + { + $response = $this->api()->search('csvimport_mappings'); + $mappings = $response->getContent(); + $mappingNames = []; + foreach ($mappings as $mapping) { + $mappingNames[] = $mapping->name(); + } + + $query = $this->params()->fromQuery(); + + $jobId = null; + if ($this->getRequest()->isPost()) { + if (!empty($this->params()->fromPost()['job_id'])) + $jobId = $this->params()->fromPost()['job_id']; + else { + $this->messenger()->addError('Job id not provided.'); // @translate; + return $this->redirect()->toRoute('admin/csvimport/past-imports', ['action' => 'browse'], true); + } + } + else { + if (!empty($query['job_id'])) { + $jobId = $query['job_id']; + } + else { + return $this->getResponse()->setStatusCode(404)->setContent('Job id not provided.'); // @translate + } + } + + $view = new ViewModel; + $form = $this->getForm(MappingSaveForm::class, ['job_id' => $jobId]); + $view->setVariable('form', $form); + $view->setTerminal(true); + $view->setTemplate('csv-import/admin/mapping/save-mapping'); + $view->setVariable('mappings', $mappingNames); + + if ($this->getRequest()->isPost()) { + $data = $this->params()->fromPost(); + $form->setData($data); + + if ($form->isValid()) { + + $job = null; + $job = $this->api()->read('jobs', $jobId)->getContent(); + if (empty($job)) { + $this->messenger()->addError('Could not find job with id %s.', $jobId); // @translate; + return $this->redirect()->toRoute('admin/csvimport/past-imports', ['action' => 'browse'], true); + } + + $args = $job->args(); + $args['override_mapping'] = $data['override_mapping'] ?? null; + $args['mapping_name'] = $data['mapping_name']; + if (!$this->saveMapping($args)) { + // TODO Keep user variables when the form is invalid. + $this->messenger()->addError('A mapping with that name already exists.'); // @translate + return $this->redirect()->toRoute('admin/csvimport/past-imports', ['action' => 'browse'], true); + } + else { + $this->messenger()->addSuccess(sprintf('Mapping successfully saved as %s.', // @translate + $data['mapping_name'])); + return $this->redirect()->toRoute('admin/csvimport/past-imports', ['action' => 'browse'], true); + } + } + $this->messenger()->addFormErrors($form); + return $this->redirect()->toRoute('admin/csvimport/past-imports', ['action' => 'browse'], true); + } + + return $view; + } + /* * meant for JS */ diff --git a/src/Controller/IndexController.php b/src/Controller/IndexController.php index b4d7986b..5fc47392 100644 --- a/src/Controller/IndexController.php +++ b/src/Controller/IndexController.php @@ -161,10 +161,10 @@ public function mapAction() } $args = $this->cleanArgs($post); + $session = new \Laminas\Session\Container('CsvImport'); + $args['columns'] = $session->columns; $this->saveUserSettings($args); - if (isset($post['save_mapping'])) { - $this->saveMapping($args, []); - } + $dispatcher = $this->jobDispatcher(); $job = $dispatcher->dispatch('CSVImport\Job\Import', $args); // The CsvImport record is created in the job, so it doesn't @@ -467,55 +467,4 @@ protected function saveUserSettings(array $settings) } } } - - /** - * Save mapping. - */ - protected function saveMapping(array $args): void - { - // We first need to read the file to get the column names - // Because we need to remember the column names - $filePath = $args['filepath']; - $fileName = $args['filename']; - - // Check if file exists and is readable - if (!file_exists($filePath) || !is_readable($filePath)) { - $this->logger()->err(sprintf("[CSV Import]: File '%s' not found when saving mapping.", $filePath)); // @translate - } - - // Open the file for reading - if (($handle = fopen($filePath, 'r')) !== false) { - // Read the first line as CSV (header row) - $args['columns'] = fgetcsv($handle); - - // Close file - fclose($handle); - - // Output the column names - if (!$args['columns']) { - $this->logger()->err(sprintf("[CSV Import]: Unable to read columns when saving mapping.")); // @translate - } - } else { - $this->logger()->err(sprintf("[CSV Import]: File '%s' could not be opened when saving mapping.", $filePath)); // @translate - } - - if (empty($args['columns'])) { - $this->logger()->err(sprintf("[CSV Import]: Unable to get columns from file '%s'.", $filePath)); // @translate - } - - $this->logger()->debug(sprintf("[CSV Import] Column names: " . PHP_EOL . "%s" . PHP_EOL, json_encode($args["columns"]))); - - // don't save irrelevant data - unset($args['filename']); - unset($args['filesize']); - unset($args['filepath']); - unset($args['media_type']); - unset($args['resource_type']); - unset($args['automap_check_names_alone']); - unset($args['save_mapping']); - - $this->logger()->debug(sprintf('[CSV Import: Args to be saved my mapping]' . PHP_EOL . '%s' . PHP_EOL, json_encode($args))); - - $this->api()->create('csvimport_mappings', ['mapping' => json_encode($args), 'name' => $fileName]); - } } diff --git a/view/csv-import/admin/mapping/edit.phtml b/view/csv-import/admin/mapping/edit.phtml index 627ae1e2..834700c6 100644 --- a/view/csv-import/admin/mapping/edit.phtml +++ b/view/csv-import/admin/mapping/edit.phtml @@ -1,6 +1,6 @@ prepare(); ?> -pageTitle($this->translate('Edit model'), 3); ?> +pageTitle($this->translate('Edit mapping'), 3); ?> form()->openTag($form); ?> diff --git a/view/csv-import/index/map.phtml b/view/csv-import/index/map.phtml index 807618f3..11a995af 100644 --- a/view/csv-import/index/map.phtml +++ b/view/csv-import/index/map.phtml @@ -40,25 +40,6 @@ $pageTitle = isset($resourceTypeLabels[$resourceType]) formCollection($form); ?>
-
    -
  • hyperlink( - '', - '#', - [ - 'data-sidebar-content-url' => $this->url('admin/csvimport/mapping', - [ - 'controller' => 'Mapping', - 'action' => 'selectMapping', - ] - ), - 'class' => 'o-icon-menu sidebar-content', - 'title' => $this->translate('Select mapping'), - 'data-sidebar-selector' => '#sidebar', - ] - ); ?> - translate('Load a saved mapping'); ?> -
  • -
@@ -79,9 +60,26 @@ $pageTitle = isset($resourceTypeLabels[$resourceType]) -
- - +
+
    +
  • hyperlink( + '', + '#', + [ + 'data-sidebar-content-url' => $this->url('admin/csvimport/mapping', + [ + 'controller' => 'Mapping', + 'action' => 'selectMapping', + ] + ), + 'class' => 'o-icon-menu sidebar-content', + 'title' => $this->translate('Select mapping'), + 'data-sidebar-selector' => '#sidebar', + ] + ); ?> + translate('Load a saved mapping'); ?> +
  • +
diff --git a/view/csv-import/index/past-imports.phtml b/view/csv-import/index/past-imports.phtml index 8b7a80fe..8ebe6e9a 100644 --- a/view/csv-import/index/past-imports.phtml +++ b/view/csv-import/index/past-imports.phtml @@ -26,6 +26,7 @@ $this->headLink()->appendStylesheet($this->assetUrl('css/csvimport.css', 'CSVImp translate('Result'));?> translate('Status'));?> translate('Owner'));?> + translate('Save'));?> @@ -103,9 +104,43 @@ $this->headLink()->appendStylesheet($this->assetUrl('css/csvimport.css', 'CSVImp echo $this->hyperlink($owner->name(), $this->url('admin/id', array('controller' => 'user', 'action' => 'show', 'id' => $owner->id()))); endif; ?> + + hyperlink( + '', + '#', + [ + 'data-sidebar-content-url' => $this->url( + 'admin/csvimport/mapping', + [ + 'controller' => 'Mapping', + 'action' => 'save', + ], + [ + 'query' => [ + 'job_id' => $job->id(), + ], + ] + ), + 'class' => 'fa fal fa-save sidebar-content', + 'title' => $escape($this->translate('Save')), + 'data-sidebar-selector' => '#sidebar', + ], + ); + } ?> + + + From 1c75e2917c4cf3442eeec7754271661cf933695e Mon Sep 17 00:00:00 2001 From: Abel B Date: Thu, 8 Jan 2026 17:15:25 +0100 Subject: [PATCH 21/21] Rename mapping to mapping model. --- Module.php | 6 +- asset/js/csvimport.js | 2 +- config/module.config.php | 36 +++++------ .../__CG__CSVImportEntityCSVImportMapping.php | 4 +- ...ingAdapter.php => MappingModelAdapter.php} | 14 ++--- ...ion.php => MappingModelRepresentation.php} | 8 +-- ...troller.php => MappingModelController.php} | 60 +++++++++---------- src/Controller/IndexController.php | 6 +- ...tMapping.php => CSVImportMappingModel.php} | 2 +- ...ppingSelect.php => MappingModelSelect.php} | 4 +- ...gEditForm.php => MappingModelEditForm.php} | 2 +- .../{MappingForm.php => MappingModelForm.php} | 14 ++--- ...gSaveForm.php => MappingModelSaveForm.php} | 8 +-- ...ectForm.php => MappingModelSelectForm.php} | 12 ++-- .../{LoadMapping.php => LoadMappingModel.php} | 4 +- .../{SaveMapping.php => SaveMappingModel.php} | 28 ++++----- ....php => MappingModelControllerFactory.php} | 6 +- ...actory.php => LoadMappingModelFactory.php} | 6 +- ...actory.php => SaveMappingModelFactory.php} | 6 +- ...tory.php => MappingModelSelectFactory.php} | 6 +- ...actory.php => MappingModelFormFactory.php} | 6 +- ...ry.php => MappingModelSaveFormFactory.php} | 6 +- .../{mapping => mapping-model}/browse.phtml | 16 ++--- .../{mapping => mapping-model}/edit.phtml | 2 +- .../save-mapping-model.phtml} | 2 +- .../select-mapping-model.phtml} | 4 +- .../{mapping => mapping-model}/show.phtml | 2 +- view/csv-import/index/map.phtml | 10 ++-- view/csv-import/index/past-imports.phtml | 4 +- 29 files changed, 143 insertions(+), 143 deletions(-) rename src/Api/Adapter/{MappingAdapter.php => MappingModelAdapter.php} (69%) rename src/Api/Representation/{MappingRepresentation.php => MappingModelRepresentation.php} (84%) rename src/Controller/Admin/{MappingController.php => MappingModelController.php} (78%) rename src/Entity/{CSVImportMapping.php => CSVImportMappingModel.php} (96%) rename src/Form/Element/{MappingSelect.php => MappingModelSelect.php} (88%) rename src/Form/{MappingEditForm.php => MappingModelEditForm.php} (90%) rename src/Form/{MappingForm.php => MappingModelForm.php} (97%) rename src/Form/{MappingSaveForm.php => MappingModelSaveForm.php} (73%) rename src/Form/{MappingSelectForm.php => MappingModelSelectForm.php} (61%) rename src/Mvc/Controller/Plugin/{LoadMapping.php => LoadMappingModel.php} (98%) rename src/Mvc/Controller/Plugin/{SaveMapping.php => SaveMappingModel.php} (73%) rename src/Service/Controller/Admin/{MappingControllerFactory.php => MappingModelControllerFactory.php} (62%) rename src/Service/ControllerPlugin/{SaveMappingFactory.php => LoadMappingModelFactory.php} (73%) rename src/Service/ControllerPlugin/{LoadMappingFactory.php => SaveMappingModelFactory.php} (73%) rename src/Service/Form/Element/{MappingSelectFactory.php => MappingModelSelectFactory.php} (70%) rename src/Service/Form/{MappingFormFactory.php => MappingModelFormFactory.php} (67%) rename src/Service/Form/{MappingSaveFormFactory.php => MappingModelSaveFormFactory.php} (73%) rename view/csv-import/admin/{mapping => mapping-model}/browse.phtml (90%) rename view/csv-import/admin/{mapping => mapping-model}/edit.phtml (78%) rename view/csv-import/admin/{mapping/save-mapping.phtml => mapping-model/save-mapping-model.phtml} (93%) rename view/csv-import/admin/{mapping/select-mapping.phtml => mapping-model/select-mapping-model.phtml} (64%) rename view/csv-import/admin/{mapping => mapping-model}/show.phtml (98%) diff --git a/Module.php b/Module.php index 72111155..02fbcd98 100644 --- a/Module.php +++ b/Module.php @@ -21,7 +21,7 @@ public function install(ServiceLocatorInterface $serviceLocator) { $connection = $serviceLocator->get('Omeka\Connection'); $sql = <<<'SQL' -CREATE TABLE csvimport_mapping ( +CREATE TABLE csvimport_mapping_model ( id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, created DATETIME NOT NULL, @@ -68,7 +68,7 @@ public function uninstall(ServiceLocatorInterface $serviceLocator) ALTER TABLE csvimport_import DROP FOREIGN KEY FK_17B50881BE04EA9; DROP TABLE IF EXISTS csvimport_entity; DROP TABLE IF EXISTS csvimport_import; -DROP TABLE IF EXISTS csvimport_mapping; +DROP TABLE IF EXISTS csvimport_mapping_model; SQL; $sqls = array_filter(array_map('trim', explode(';', $sql))); foreach ($sqls as $sql) { @@ -95,7 +95,7 @@ public function upgrade($oldVersion, $newVersion, ServiceLocatorInterface $servi if (version_compare($oldVersion, '2.7.0', '<')) { $connection = $serviceLocator->get('Omeka\Connection'); $sql = <<<'SQL' -CREATE TABLE csvimport_mapping ( +CREATE TABLE csvimport_mapping_model ( id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, created DATETIME NOT NULL, diff --git a/asset/js/csvimport.js b/asset/js/csvimport.js index 0b2395cf..74bb8119 100644 --- a/asset/js/csvimport.js +++ b/asset/js/csvimport.js @@ -13,7 +13,7 @@ var defaultSidebarHtml = null; var actionsHtml = '
    ' - + '
  • ' + + '
  • ' + '
'; var batchEditCheckboxes = $('.column-select, .select-all'); diff --git a/config/module.config.php b/config/module.config.php index bcc84ba7..9c85cf83 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -25,28 +25,28 @@ ], 'form_elements' => [ 'invokables' => [ - 'CSVImport\Form\MappingEditForm' => Form\MappingEditForm::class, - 'CSVImport\Form\MappingSelectForm' => Form\MappingSelectForm::class, + 'CSVImport\Form\MappingModelEditForm' => Form\MappingModelEditForm::class, + 'CSVImport\Form\MappingModelSelectForm' => Form\MappingModelSelectForm::class, ], 'factories' => [ 'CSVImport\Form\ImportForm' => Service\Form\ImportFormFactory::class, - 'CSVImport\Form\MappingForm' => Service\Form\MappingFormFactory::class, - 'CSVImport\Form\Element\MappingSelect' => Service\Form\Element\MappingSelectFactory::class, - 'CSVImport\Form\MappingSaveForm' => Service\Form\MappingSaveFormFactory::class, + 'CSVImport\Form\MappingModelForm' => Service\Form\MappingModelFormFactory::class, + 'CSVImport\Form\Element\MappingModelSelect' => Service\Form\Element\MappingModelSelectFactory::class, + 'CSVImport\Form\MappingModelSaveForm' => Service\Form\MappingModelSaveFormFactory::class, ], ], 'controllers' => [ 'factories' => [ 'CSVImport\Controller\Index' => Service\Controller\IndexControllerFactory::class, - 'CSVImport\Controller\Admin\Mapping' => Service\Controller\Admin\MappingControllerFactory::class, + 'CSVImport\Controller\Admin\MappingModel' => Service\Controller\Admin\MappingModelControllerFactory::class, ], ], 'controller_plugins' => [ 'factories' => [ 'automapHeadersToMetadata' => Service\ControllerPlugin\AutomapHeadersToMetadataFactory::class, 'findResourcesFromIdentifiers' => Service\ControllerPlugin\FindResourcesFromIdentifiersFactory::class, - 'loadMapping' => Service\ControllerPlugin\LoadMappingFactory::class, - 'saveMapping' => Service\ControllerPlugin\SaveMappingFactory::class, + 'loadMappingModel' => Service\ControllerPlugin\LoadMappingModelFactory::class, + 'saveMappingModel' => Service\ControllerPlugin\SaveMappingModelFactory::class, ], 'aliases' => [ 'findResourceFromIdentifier' => 'findResourcesFromIdentifiers', @@ -56,7 +56,7 @@ 'invokables' => [ 'csvimport_entities' => Api\Adapter\EntityAdapter::class, 'csvimport_imports' => Api\Adapter\ImportAdapter::class, - 'csvimport_mappings' => Api\Adapter\MappingAdapter::class, + 'csvimport_mapping_models' => Api\Adapter\MappingModelAdapter::class, ], ], 'service_manager' => [ @@ -102,31 +102,31 @@ ], ], ], - 'mapping' => [ + 'mapping-model' => [ 'type' => 'Segment', 'options' => [ - 'route' => '/mapping[/:action]', + 'route' => '/mapping-model[/:action]', 'constraints' => [ 'action' => '[a-zA-Z][a-zA-Z0-9_-]*', ], 'defaults' => [ '__NAMESPACE__' => 'CSVImport\Controller\Admin', - 'controller' => 'Mapping', + 'controller' => 'MappingModel', 'action' => 'browse', ], ], ], - 'mapping-id' => [ + 'mapping-model-id' => [ 'type' => 'Segment', 'options' => [ - 'route' => '/mapping/:id[/:action]', + 'route' => '/mapping-model/:id[/:action]', 'constraints' => [ 'action' => '[a-zA-Z][a-zA-Z0-9_-]*', 'id' => '\d+', ], 'defaults' => [ '__NAMESPACE__' => 'CSVImport\Controller\Admin', - 'controller' => 'Mapping', + 'controller' => 'MappingModel', 'action' => 'show', ], ], @@ -163,8 +163,8 @@ 'resource' => 'CSVImport\Controller\Index', ], [ - 'label' => 'Mappings', // @translate - 'route' => 'admin/csvimport/mapping', + 'label' => 'Mapping Models', // @translate + 'route' => 'admin/csvimport/mapping-model', ], ], ], @@ -181,7 +181,7 @@ ], ], 'js_translate_strings' => [ - 'Remove mapping', // @translate + 'Remove mapping model', // @translate ], 'csv_import' => [ 'sources' => [ diff --git a/data/doctrine-proxies/__CG__CSVImportEntityCSVImportMapping.php b/data/doctrine-proxies/__CG__CSVImportEntityCSVImportMapping.php index 430878ab..11ca22aa 100644 --- a/data/doctrine-proxies/__CG__CSVImportEntityCSVImportMapping.php +++ b/data/doctrine-proxies/__CG__CSVImportEntityCSVImportMapping.php @@ -6,7 +6,7 @@ /** * DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE'S PROXY GENERATOR */ -class CSVImportMapping extends \CSVImport\Entity\CSVImportMapping implements \Doctrine\ORM\Proxy\Proxy +class CSVImportMappingModel extends \CSVImport\Entity\CSVImportMappingModel implements \Doctrine\ORM\Proxy\Proxy { /** * @var \Closure the callback responsible for loading properties in the proxy object. This callback is called with @@ -79,7 +79,7 @@ public function __sleep() public function __wakeup() { if ( ! $this->__isInitialized__) { - $this->__initializer__ = function (CSVImportMapping $proxy) { + $this->__initializer__ = function (CSVImportMappingModel $proxy) { $proxy->__setInitializer(null); $proxy->__setCloner(null); diff --git a/src/Api/Adapter/MappingAdapter.php b/src/Api/Adapter/MappingModelAdapter.php similarity index 69% rename from src/Api/Adapter/MappingAdapter.php rename to src/Api/Adapter/MappingModelAdapter.php index 58df9ca2..22f10dc3 100644 --- a/src/Api/Adapter/MappingAdapter.php +++ b/src/Api/Adapter/MappingModelAdapter.php @@ -5,24 +5,24 @@ use Omeka\Api\Request; use Omeka\Entity\EntityInterface; use Omeka\Stdlib\ErrorStore; -use CSVImport\Entity\CSVImportMapping; +use CSVImport\Entity\CSVImportMappingModel; use Doctrine\ORM\QueryBuilder; -class MappingAdapter extends AbstractEntityAdapter +class MappingModelAdapter extends AbstractEntityAdapter { public function getResourceName() { - return 'csvimport_mappings'; + return 'csvimport_mapping_models'; } public function getRepresentationClass() { - return \CSVImport\Api\Representation\MappingRepresentation::class; + return \CSVImport\Api\Representation\MappingModelRepresentation::class; } public function getEntityClass() { - return CSVImportMapping::class; + return CSVImportMappingModel::class; } public function hydrate(Request $request, EntityInterface $entity, @@ -42,11 +42,11 @@ public function hydrate(Request $request, EntityInterface $entity, public function validateEntity(EntityInterface $entity, ErrorStore $errorStore) { if (!$entity->getName()) { - $errorStore->addError('o-module-csvimport-mapping:name', 'A model must have a name to save it.'); // @translate + $errorStore->addError('o-module-csvimport-mappingmodel:name', 'A model must have a name to save it.'); // @translate } if (!$entity->getMapping()) { - $errorStore->addError('o-module-csvimport-mapping:mapping', 'Mapping must exists.'); // @translate + $errorStore->addError('o-module-csvimport-mappingmodel:mapping', 'Mapping model must exists.'); // @translate } } diff --git a/src/Api/Representation/MappingRepresentation.php b/src/Api/Representation/MappingModelRepresentation.php similarity index 84% rename from src/Api/Representation/MappingRepresentation.php rename to src/Api/Representation/MappingModelRepresentation.php index a0522b74..748ab3af 100644 --- a/src/Api/Representation/MappingRepresentation.php +++ b/src/Api/Representation/MappingModelRepresentation.php @@ -3,11 +3,11 @@ use Omeka\Api\Representation\AbstractEntityRepresentation; -class MappingRepresentation extends AbstractEntityRepresentation +class MappingModelRepresentation extends AbstractEntityRepresentation { public function getControllerName() { - return 'mapping'; + return 'mappingmodel'; } public function getJsonLd() @@ -21,7 +21,7 @@ public function getJsonLd() public function getJsonLdType() { - return 'o:CSVimportMapping'; + return 'o:CSVimportMappingModel'; } public function name() @@ -43,7 +43,7 @@ public function adminUrl($action = null, $canonical = false) { $url = $this->getViewHelper('Url'); return $url( - 'admin/csvimport/mapping-id', + 'admin/csvimport/mapping-model-id', [ 'controller' => $this->getControllerName(), 'action' => $action, diff --git a/src/Controller/Admin/MappingController.php b/src/Controller/Admin/MappingModelController.php similarity index 78% rename from src/Controller/Admin/MappingController.php rename to src/Controller/Admin/MappingModelController.php index 1912f5db..e9671029 100644 --- a/src/Controller/Admin/MappingController.php +++ b/src/Controller/Admin/MappingModelController.php @@ -5,16 +5,16 @@ use Laminas\Mvc\Controller\AbstractActionController; use Laminas\View\Model\ViewModel; use Omeka\Form\ConfirmForm; -use CSVImport\Form\MappingEditForm; -use CSVImport\Form\MappingSelectForm; -use CSVImport\Form\MappingSaveForm; +use CSVImport\Form\MappingModelEditForm; +use CSVImport\Form\MappingModelSelectForm; +use CSVImport\Form\MappingModelSaveForm; -class MappingController extends AbstractActionController +class MappingModelController extends AbstractActionController { public function browseAction() { $this->setBrowseDefaults('created'); - $response = $this->api()->search('csvimport_mappings'); + $response = $this->api()->search('csvimport_mapping_models'); $this->paginator($response->getTotalResults()); @@ -38,7 +38,7 @@ public function showAction() $propertiesMap[$property->id()] = $property->term(); } - $mappingModel = $this->loadMapping($this->params('id'), []); + $mappingModel = $this->loadMappingModel($this->params('id'), []); $view = new ViewModel; $view->setVariable('propertiesMap', $propertiesMap); @@ -51,7 +51,7 @@ public function showAction() public function saveAction() { - $response = $this->api()->search('csvimport_mappings'); + $response = $this->api()->search('csvimport_mapping_models'); $mappings = $response->getContent(); $mappingNames = []; foreach ($mappings as $mapping) { @@ -79,10 +79,10 @@ public function saveAction() } $view = new ViewModel; - $form = $this->getForm(MappingSaveForm::class, ['job_id' => $jobId]); + $form = $this->getForm(MappingModelSaveForm::class, ['job_id' => $jobId]); $view->setVariable('form', $form); $view->setTerminal(true); - $view->setTemplate('csv-import/admin/mapping/save-mapping'); + $view->setTemplate('csv-import/admin/mapping-model/save-mapping-model'); $view->setVariable('mappings', $mappingNames); if ($this->getRequest()->isPost()) { @@ -101,9 +101,9 @@ public function saveAction() $args = $job->args(); $args['override_mapping'] = $data['override_mapping'] ?? null; $args['mapping_name'] = $data['mapping_name']; - if (!$this->saveMapping($args)) { + if (!$this->saveMappingModel($args)) { // TODO Keep user variables when the form is invalid. - $this->messenger()->addError('A mapping with that name already exists.'); // @translate + $this->messenger()->addError('A mapping model with that name already exists.'); // @translate return $this->redirect()->toRoute('admin/csvimport/past-imports', ['action' => 'browse'], true); } else { @@ -122,16 +122,16 @@ public function saveAction() /* * meant for JS */ - public function selectMappingAction() + public function selectMappingModelAction() { - $response = $this->api()->search('csvimport_mappings'); + $response = $this->api()->search('csvimport_mapping_models'); $mappings = $response->getContent(); $view = new ViewModel; - $form = $this->getForm(MappingSelectForm::class); + $form = $this->getForm(MappingModelSelectForm::class); $view->setVariable('form', $form); $view->setTerminal(true); - $view->setTemplate('csv-import/admin/mapping/select-mapping'); + $view->setTemplate('csv-import/admin/mapping-model/select-mapping-model'); if ($this->getRequest()->isPost()) { $data = $this->params()->fromPost(); @@ -143,10 +143,10 @@ public function selectMappingAction() $columns = $session->columns; - $response = $this->api()->read('csvimport_mappings', $mappingId); + $response = $this->api()->read('csvimport_mapping_models', $mappingId); if ($response) { $view = new ViewModel([ - 'automaps' => $this->loadMapping($mappingId, $columns), + 'automaps' => $this->loadMappingModel($mappingId, $columns), 'columns' => $columns, 'resourceType' => $session->resourceType, ]); @@ -154,10 +154,10 @@ public function selectMappingAction() $view->setTerminal(true); // no layout return $view; } else { - return $this->getResponse()->setStatusCode(404)->setContent('Mapping not found.'); // @translate + return $this->getResponse()->setStatusCode(404)->setContent('Mapping model not found.'); // @translate } } - return $this->getResponse()->setStatusCode(400)->setContent('Mapping selection form not valid.'); + return $this->getResponse()->setStatusCode(400)->setContent('Mapping model selection form not valid.'); } return $view; @@ -165,11 +165,11 @@ public function selectMappingAction() public function editAction() { - $response = $this->api()->read('csvimport_mappings', $this->params('id')); + $response = $this->api()->read('csvimport_mapping_models', $this->params('id')); $mapping = $response->getContent(); $view = new ViewModel; - $form = $this->getForm(MappingEditForm::class); + $form = $this->getForm(MappingModelEditForm::class); $form->setAttribute('action', $mapping->url('edit')); $form->setData([ 'model_name' => $mapping->name(), @@ -177,7 +177,7 @@ public function editAction() $view->setVariable('form', $form); $view->setTerminal(true); - $view->setTemplate('csv-import/admin/mapping/edit'); + $view->setTemplate('csv-import/admin/mapping-model/edit'); $view->setVariable('mapping', $mapping); if ($this->getRequest()->isPost()) { @@ -186,11 +186,11 @@ public function editAction() if ($form->isValid()) { $mappingName = $form->get('model_name')->getValue(); - $response = $this->api($form)->update('csvimport_mappings', $this->params('id'), ['name' => $mappingName], [], ['isPartial' => true]); + $response = $this->api($form)->update('csvimport_mapping_models', $this->params('id'), ['name' => $mappingName], [], ['isPartial' => true]); if ($response) { - $this->messenger()->addSuccess('Mapping successfully updated'); // @translate + $this->messenger()->addSuccess('Mapping model successfully updated'); // @translate return $this->redirect()->toRoute( - 'admin/csvimport/mapping', + 'admin/csvimport/mapping-model', ['action' => 'browse'], true ); @@ -198,7 +198,7 @@ public function editAction() } else { $this->messenger()->addFormErrors($form); return $this->redirect()->toRoute( - 'admin/csvimport/mapping', + 'admin/csvimport/mapping-model', ['action' => 'browse'], true ); @@ -209,7 +209,7 @@ public function editAction() public function deleteConfirmAction() { - $response = $this->api()->read('csvimport_mappings', $this->params('id')); + $response = $this->api()->read('csvimport_mapping_models', $this->params('id')); $mappingModel = $response->getContent(); $view = new ViewModel; @@ -226,16 +226,16 @@ public function deleteAction() $form = $this->getForm(ConfirmForm::class); $form->setData($this->getRequest()->getPost()); if ($form->isValid()) { - $response = $this->api($form)->delete('csvimport_mappings', $this->params('id')); + $response = $this->api($form)->delete('csvimport_mapping_models', $this->params('id')); if ($response) { - $this->messenger()->addSuccess('Mapping successfully deleted'); // @translate + $this->messenger()->addSuccess('Mapping model successfully deleted'); // @translate } } else { $this->messenger()->addFormErrors($form); } } return $this->redirect()->toRoute( - 'admin/csvimport/mapping', + 'admin/csvimport/mapping-model', ['action' => 'browse'], true ); diff --git a/src/Controller/IndexController.php b/src/Controller/IndexController.php index 5fc47392..11608b97 100644 --- a/src/Controller/IndexController.php +++ b/src/Controller/IndexController.php @@ -2,7 +2,7 @@ namespace CSVImport\Controller; use CSVImport\Form\ImportForm; -use CSVImport\Form\MappingForm; +use CSVImport\Form\MappingModelForm; use CSVImport\Source\SourceInterface; use CSVImport\Job\Import; use finfo; @@ -129,7 +129,7 @@ public function mapAction() $session->resourceType = $resourceType; $mappingOptions['columns'] = $columns; - $form = $this->getForm(MappingForm::class, $mappingOptions); + $form = $this->getForm(MappingModelForm::class, $mappingOptions); $automapOptions = []; $automapOptions['check_names_alone'] = $args['automap_check_names_alone']; @@ -151,7 +151,7 @@ public function mapAction() return $view; } else { - $form = $this->getForm(MappingForm::class, $mappingOptions); + $form = $this->getForm(MappingModelForm::class, $mappingOptions); $form->setData($post); if ($form->isValid()) { if (isset($post['basic-settings']) || isset($post['advanced-settings'])) { diff --git a/src/Entity/CSVImportMapping.php b/src/Entity/CSVImportMappingModel.php similarity index 96% rename from src/Entity/CSVImportMapping.php rename to src/Entity/CSVImportMappingModel.php index 749b5a02..c247d567 100644 --- a/src/Entity/CSVImportMapping.php +++ b/src/Entity/CSVImportMappingModel.php @@ -17,7 +17,7 @@ * } * ) */ -class CSVImportMapping extends AbstractEntity +class CSVImportMappingModel extends AbstractEntity { /** * @Id diff --git a/src/Form/Element/MappingSelect.php b/src/Form/Element/MappingModelSelect.php similarity index 88% rename from src/Form/Element/MappingSelect.php rename to src/Form/Element/MappingModelSelect.php index 1a1cfebd..f929f395 100644 --- a/src/Form/Element/MappingSelect.php +++ b/src/Form/Element/MappingModelSelect.php @@ -3,7 +3,7 @@ use Omeka\Api\Manager as ApiManager; -class MappingSelect extends \Laminas\Form\Element\Select +class MappingModelSelect extends \Laminas\Form\Element\Select { /** * @var ApiManager @@ -29,7 +29,7 @@ public function getApiManager() public function getValueOptions(): array { $valueOptions = []; - $mappings = $this->apiManager->search("csvimport_mappings", [])->getContent(); + $mappings = $this->apiManager->search("csvimport_mapping_models", [])->getContent(); foreach ($mappings as $mapping) { $valueOptions[$mapping->id()] = $mapping->name(); } diff --git a/src/Form/MappingEditForm.php b/src/Form/MappingModelEditForm.php similarity index 90% rename from src/Form/MappingEditForm.php rename to src/Form/MappingModelEditForm.php index 82d907aa..4dc5788b 100644 --- a/src/Form/MappingEditForm.php +++ b/src/Form/MappingModelEditForm.php @@ -4,7 +4,7 @@ use Laminas\Form\Form; -class MappingEditForm extends Form +class MappingModelEditForm extends Form { public function init() { diff --git a/src/Form/MappingForm.php b/src/Form/MappingModelForm.php similarity index 97% rename from src/Form/MappingForm.php rename to src/Form/MappingModelForm.php index 2db56d78..a5e4e4ce 100644 --- a/src/Form/MappingForm.php +++ b/src/Form/MappingModelForm.php @@ -9,7 +9,7 @@ use Omeka\Form\Element\SiteSelect; use Laminas\Form\Form; -class MappingForm extends Form +class MappingModelForm extends Form { protected $serviceLocator; @@ -84,7 +84,7 @@ public function init() 'type' => ResourceSelect::class, 'options' => [ 'label' => 'Resource template', // @translate - 'info' => 'Assign a resource template to all imported resources. Specific mappings can override this setting.', // @translate + 'info' => 'Assign a resource template to all imported resources. Specific mapping models can override this setting.', // @translate 'empty_option' => 'Select a template', // @translate 'resource_value_options' => [ 'resource' => 'resource_templates', @@ -107,7 +107,7 @@ public function init() 'type' => ResourceClassSelect::class, 'options' => [ 'label' => 'Class', // @translate - 'info' => 'Assign a resource class to all imported resources. Specific mappings can override this setting.', // @translate + 'info' => 'Assign a resource class to all imported resources. Specific mapping models can override this setting.', // @translate 'empty_option' => 'Select a class', // @translate ], 'attributes' => [ @@ -153,7 +153,7 @@ public function init() 'type' => 'radio', 'options' => [ 'label' => 'Visibility', // @translate - 'info' => 'Set visibility for all imported resources. Specific mappings can override this setting.', // @translate + 'info' => 'Set visibility for all imported resources. Specific mapping models can override this setting.', // @translate 'value_options' => [ '1' => 'Public', // @translate '0' => 'Private', // @translate @@ -171,7 +171,7 @@ public function init() 'type' => 'radio', 'options' => [ 'label' => 'Open/closed to additions', // @translate - 'info' => 'Set whether imported item sets are open to additions. Specific mappings can override this setting.', // @translate + 'info' => 'Set whether imported item sets are open to additions. Specific mapping models can override this setting.', // @translate 'value_options' => [ '1' => 'Open', // @translate '0' => 'Closed', // @translate @@ -221,7 +221,7 @@ public function init() 'type' => 'radio', 'options' => [ 'label' => 'Item sets open/closed to additions', // @translate - 'info' => 'Set whether imported item sets are open to additions. Specific mappings can override this setting.', // @translate + 'info' => 'Set whether imported item sets are open to additions. Specific mapping models can override this setting.', // @translate 'value_options' => [ '1' => 'Open', // @translate '0' => 'Closed', // @translate @@ -284,7 +284,7 @@ public function init() 'type' => 'text', 'options' => [ 'label' => 'Language', // @translate - 'info' => 'Language setting to apply to all imported literal data. Individual property mappings can override the setting here.', // @translate + 'info' => 'Language setting to apply to all imported literal data. Individual property mapping models can override the setting here.', // @translate ], 'attributes' => [ 'id' => 'global_language', diff --git a/src/Form/MappingSaveForm.php b/src/Form/MappingModelSaveForm.php similarity index 73% rename from src/Form/MappingSaveForm.php rename to src/Form/MappingModelSaveForm.php index 59f093ba..361e83e4 100644 --- a/src/Form/MappingSaveForm.php +++ b/src/Form/MappingModelSaveForm.php @@ -5,12 +5,12 @@ use Laminas\Form\Form; use Laminas\Form\Element\Checkbox; -class MappingSaveForm extends Form +class MappingModelSaveForm extends Form { public function init() { - $this->setAttribute('action', 'mapping/save'); + $this->setAttribute('action', 'mapping-model/save'); $this->add([ 'name'=> 'job_id', @@ -24,7 +24,7 @@ public function init() 'name' => 'mapping_name', 'type' => 'text', 'options' => [ - 'label' => 'Mapping name', //@translate + 'label' => 'Mapping model name', //@translate ], 'attributes' => [ 'required' => true, @@ -34,7 +34,7 @@ public function init() 'name' => 'override_mapping', 'type' => Checkbox::class, 'options' => [ - 'label' => 'Override mapping if it already exists?', //@translate + 'label' => 'Override mapping model if it already exists?', //@translate ], ]); } diff --git a/src/Form/MappingSelectForm.php b/src/Form/MappingModelSelectForm.php similarity index 61% rename from src/Form/MappingSelectForm.php rename to src/Form/MappingModelSelectForm.php index a7d1ef87..467f49b9 100644 --- a/src/Form/MappingSelectForm.php +++ b/src/Form/MappingModelSelectForm.php @@ -1,18 +1,18 @@ setAttribute('action', '/admin/csvimport/mapping/selectMapping'); + $this->setAttribute('action', '/admin/csvimport/mapping-model/selectMappingModel'); $this->add([ 'name' => 'mapping_id', - 'type' => MappingSelect::class, + 'type' => MappingModelSelect::class, 'attributes' => [ 'id' => 'mapping-id', 'class' => 'chosen-select', @@ -20,9 +20,9 @@ public function init() 'data-placeholder' => '', ], 'options' => [ - 'label' => 'Select mapping', // @translate + 'label' => 'Select mapping model', // @translate 'resource_value_options' => [ - 'resource' => 'csvimport_mappings', + 'resource' => 'csvimport_mapping_models', 'query' => [], ], ], diff --git a/src/Mvc/Controller/Plugin/LoadMapping.php b/src/Mvc/Controller/Plugin/LoadMappingModel.php similarity index 98% rename from src/Mvc/Controller/Plugin/LoadMapping.php rename to src/Mvc/Controller/Plugin/LoadMappingModel.php index 9392327c..ad498c18 100644 --- a/src/Mvc/Controller/Plugin/LoadMapping.php +++ b/src/Mvc/Controller/Plugin/LoadMappingModel.php @@ -34,7 +34,7 @@ use Laminas\Mvc\Controller\Plugin\AbstractPlugin; use Laminas\Log\Logger; -class LoadMapping extends AbstractPlugin +class LoadMappingModel extends AbstractPlugin { /** * @var Connection @@ -69,7 +69,7 @@ public function __construct(Connection $connection, ApiManager $apiManager, Logg public function __invoke(int $id, array $columns) { // Fetch the mapping - $mapping = $this->api->read('csvimport_mappings', $id)->getContent(); + $mapping = $this->api->read('csvimport_mapping_models', $id)->getContent(); if (empty($mapping)) { // $this->logger()->debug(sprintf('No mapping with id %s found.', $id)); diff --git a/src/Mvc/Controller/Plugin/SaveMapping.php b/src/Mvc/Controller/Plugin/SaveMappingModel.php similarity index 73% rename from src/Mvc/Controller/Plugin/SaveMapping.php rename to src/Mvc/Controller/Plugin/SaveMappingModel.php index 72e26c23..a767372d 100644 --- a/src/Mvc/Controller/Plugin/SaveMapping.php +++ b/src/Mvc/Controller/Plugin/SaveMappingModel.php @@ -34,7 +34,7 @@ use Laminas\Mvc\Controller\Plugin\AbstractPlugin; use Laminas\Log\Logger; -class SaveMapping extends AbstractPlugin +class SaveMappingModel extends AbstractPlugin { /** * @var Connection @@ -71,10 +71,10 @@ public function __invoke(array $args): bool $shouldOverrideMapping = false; $mappingName = $args['mapping_name']; - $this->logger->debug('[CSVImport] Mapping name.'); - $this->logger->debug(json_encode($mappingName)); + // $this->logger->debug('[CSVImport] Mapping model name.'); + // $this->logger->debug(json_encode($mappingName)); - $alreadyExistsContent = $this->api->search('csvimport_mappings', ['name' => $mappingName])->getContent(); + $alreadyExistsContent = $this->api->search('csvimport_mapping_models', ['name' => $mappingName])->getContent(); if (count($alreadyExistsContent) > 0) { if (!empty($args['override_mapping'])) { @@ -82,8 +82,8 @@ public function __invoke(array $args): bool } else { - $this->logger->debug('[CSVImport] Already existing mapping.'); - $this->logger->debug(json_encode($alreadyExistsContent)); + // $this->logger->debug('[CSVImport] Already existing mapping model.'); + // $this->logger->debug(json_encode($alreadyExistsContent)); return false; } } @@ -96,7 +96,7 @@ public function __invoke(array $args): bool // Check if file exists and is readable if (!file_exists($filePath) || !is_readable($filePath)) { - $this->logger->err(sprintf("[CSV Import]: File '%s' not found when saving mapping.", $filePath)); // @translate + // $this->logger->err(sprintf("[CSV Import]: File '%s' not found when saving mapping model.", $filePath)); // @translate } // Open the file for reading @@ -109,18 +109,18 @@ public function __invoke(array $args): bool // Output the column names if (!$args['columns']) { - $this->logger->err(sprintf("[CSV Import]: Unable to read columns when saving mapping.")); // @translate + // $this->logger->err(sprintf("[CSV Import]: Unable to read columns when saving mapping model.")); // @translate } } else { - $this->logger->err(sprintf("[CSV Import]: File '%s' could not be opened when saving mapping.", $filePath)); // @translate + // $this->logger->err(sprintf("[CSV Import]: File '%s' could not be opened when saving mapping model.", $filePath)); // @translate } if (empty($args['columns'])) { - $this->logger->err(sprintf("[CSV Import]: Unable to get columns from file '%s'.", $filePath)); // @translate + // $this->logger->err(sprintf("[CSV Import]: Unable to get columns from file '%s'.", $filePath)); // @translate } } - $this->logger->debug(sprintf("[CSV Import] Column names: " . PHP_EOL . "%s" . PHP_EOL, json_encode($args["columns"]))); + // $this->logger->debug(sprintf("[CSV Import] Column names: " . PHP_EOL . "%s" . PHP_EOL, json_encode($args["columns"]))); // don't save irrelevant data unset($args['filename']); @@ -132,13 +132,13 @@ public function __invoke(array $args): bool unset($args['mapping_name']); unset($args['override_mapping']); - $this->logger->debug(sprintf('[CSV Import: Args to be saved my mapping]' . PHP_EOL . '%s' . PHP_EOL, json_encode($args))); + // $this->logger->debug(sprintf('[CSV Import: Args to be saved my mapping model]' . PHP_EOL . '%s' . PHP_EOL, json_encode($args))); if ($shouldOverrideMapping) { - $this->api->update('csvimport_mappings', ['name' => $mappingName], ['mapping' => json_encode($args)], [], ['isPartial' => true]); + $this->api->update('csvimport_mapping_models', ['name' => $mappingName], ['mapping' => json_encode($args)], [], ['isPartial' => true]); } else { - $this->api->create('csvimport_mappings', ['mapping' => json_encode($args), 'name' => $mappingName]); + $this->api->create('csvimport_mapping_models', ['mapping' => json_encode($args), 'name' => $mappingName]); } return true; diff --git a/src/Service/Controller/Admin/MappingControllerFactory.php b/src/Service/Controller/Admin/MappingModelControllerFactory.php similarity index 62% rename from src/Service/Controller/Admin/MappingControllerFactory.php rename to src/Service/Controller/Admin/MappingModelControllerFactory.php index c0a3d4d7..07b98201 100644 --- a/src/Service/Controller/Admin/MappingControllerFactory.php +++ b/src/Service/Controller/Admin/MappingModelControllerFactory.php @@ -4,13 +4,13 @@ use Interop\Container\ContainerInterface; use Laminas\ServiceManager\Factory\FactoryInterface; -use CSVImport\Controller\Admin\MappingController; +use CSVImport\Controller\Admin\MappingModelController; -class MappingControllerFactory implements FactoryInterface +class MappingModelControllerFactory implements FactoryInterface { public function __invoke(ContainerInterface $serviceLocator, $requestedName, array $options = null) { - $mappingModelController = new MappingController(); + $mappingModelController = new MappingModelController(); return $mappingModelController; } diff --git a/src/Service/ControllerPlugin/SaveMappingFactory.php b/src/Service/ControllerPlugin/LoadMappingModelFactory.php similarity index 73% rename from src/Service/ControllerPlugin/SaveMappingFactory.php rename to src/Service/ControllerPlugin/LoadMappingModelFactory.php index eefba16c..46c07147 100644 --- a/src/Service/ControllerPlugin/SaveMappingFactory.php +++ b/src/Service/ControllerPlugin/LoadMappingModelFactory.php @@ -1,15 +1,15 @@ get('Omeka\Connection'), $services->get('Omeka\ApiManager'), $services->get('Omeka\Logger') diff --git a/src/Service/ControllerPlugin/LoadMappingFactory.php b/src/Service/ControllerPlugin/SaveMappingModelFactory.php similarity index 73% rename from src/Service/ControllerPlugin/LoadMappingFactory.php rename to src/Service/ControllerPlugin/SaveMappingModelFactory.php index fad56162..5040ec98 100644 --- a/src/Service/ControllerPlugin/LoadMappingFactory.php +++ b/src/Service/ControllerPlugin/SaveMappingModelFactory.php @@ -1,15 +1,15 @@ get('Omeka\Connection'), $services->get('Omeka\ApiManager'), $services->get('Omeka\Logger') diff --git a/src/Service/Form/Element/MappingSelectFactory.php b/src/Service/Form/Element/MappingModelSelectFactory.php similarity index 70% rename from src/Service/Form/Element/MappingSelectFactory.php rename to src/Service/Form/Element/MappingModelSelectFactory.php index 6a2f4a87..3471fc5e 100644 --- a/src/Service/Form/Element/MappingSelectFactory.php +++ b/src/Service/Form/Element/MappingModelSelectFactory.php @@ -2,14 +2,14 @@ namespace CSVImport\Service\Form\Element; use Interop\Container\ContainerInterface; -use CSVImport\Form\Element\MappingSelect; +use CSVImport\Form\Element\MappingModelSelect; use Laminas\ServiceManager\Factory\FactoryInterface; -class MappingSelectFactory implements FactoryInterface +class MappingModelSelectFactory implements FactoryInterface { public function __invoke(ContainerInterface $services, $requestedName, array $options = null) { - $element = new MappingSelect; + $element = new MappingModelSelect; $element->setApiManager($services->get('Omeka\ApiManager')); return $element; } diff --git a/src/Service/Form/MappingFormFactory.php b/src/Service/Form/MappingModelFormFactory.php similarity index 67% rename from src/Service/Form/MappingFormFactory.php rename to src/Service/Form/MappingModelFormFactory.php index 38c3639d..766f994e 100644 --- a/src/Service/Form/MappingFormFactory.php +++ b/src/Service/Form/MappingModelFormFactory.php @@ -1,15 +1,15 @@ setServiceLocator($services); return $form; } diff --git a/src/Service/Form/MappingSaveFormFactory.php b/src/Service/Form/MappingModelSaveFormFactory.php similarity index 73% rename from src/Service/Form/MappingSaveFormFactory.php rename to src/Service/Form/MappingModelSaveFormFactory.php index fc4b6bfd..8cb5892a 100644 --- a/src/Service/Form/MappingSaveFormFactory.php +++ b/src/Service/Form/MappingModelSaveFormFactory.php @@ -1,15 +1,15 @@ plugin('escapeHtml'); $this->htmlElement('body')->appendAttribute('class', 'mappings browse'); ?> -pageTitle($translate('Mappings'), 1, $this->translate('CSV Import')); ?> +pageTitle($translate('Mapping models'), 1, $this->translate('CSV Import')); ?> trigger('view.browse.before'); ?> @@ -28,9 +28,9 @@ $this->htmlElement('body')->appendAttribute('class', 'mappings browse');
  • hyperlink( '', - $this->url('admin/csvimport/mapping-id', + $this->url('admin/csvimport/mapping-model-id', [ - 'controller' => 'Mapping', + 'controller' => 'MappingModel', 'action' => 'show', 'id' => $model->id() ] @@ -46,9 +46,9 @@ $this->htmlElement('body')->appendAttribute('class', 'mappings browse'); '', '#', [ - 'data-sidebar-content-url' => $this->url('admin/csvimport/mapping-id', + 'data-sidebar-content-url' => $this->url('admin/csvimport/mapping-model-id', [ - 'controller' => 'Mapping', + 'controller' => 'MappingModel', 'action' => 'edit', 'id' => $model->id() ] @@ -64,9 +64,9 @@ $this->htmlElement('body')->appendAttribute('class', 'mappings browse'); '', '#', [ - 'data-sidebar-content-url' => $this->url('admin/csvimport/mapping-id', + 'data-sidebar-content-url' => $this->url('admin/csvimport/mapping-model-id', [ - 'controller' => 'Mapping', + 'controller' => 'MappingModel', 'action' => 'deleteConfirm', 'id' => $model->id() ] @@ -99,7 +99,7 @@ $this->htmlElement('body')->appendAttribute('class', 'mappings browse');

    ');?>

    -

    +

    %s', $translate('Warning'))); ?>

    diff --git a/view/csv-import/admin/mapping/edit.phtml b/view/csv-import/admin/mapping-model/edit.phtml similarity index 78% rename from view/csv-import/admin/mapping/edit.phtml rename to view/csv-import/admin/mapping-model/edit.phtml index 834700c6..2b0a6331 100644 --- a/view/csv-import/admin/mapping/edit.phtml +++ b/view/csv-import/admin/mapping-model/edit.phtml @@ -1,6 +1,6 @@ prepare(); ?> -pageTitle($this->translate('Edit mapping'), 3); ?> +pageTitle($this->translate('Edit mapping model'), 3); ?> form()->openTag($form); ?> diff --git a/view/csv-import/admin/mapping/save-mapping.phtml b/view/csv-import/admin/mapping-model/save-mapping-model.phtml similarity index 93% rename from view/csv-import/admin/mapping/save-mapping.phtml rename to view/csv-import/admin/mapping-model/save-mapping-model.phtml index 77074497..88d7acd8 100644 --- a/view/csv-import/admin/mapping/save-mapping.phtml +++ b/view/csv-import/admin/mapping-model/save-mapping-model.phtml @@ -1,6 +1,6 @@ prepare(); ?> -pageTitle($this->translate('Save mapping'), 3); ?> +pageTitle($this->translate('Save mapping model'), 3); ?> form()->openTag($form); ?> diff --git a/view/csv-import/admin/mapping/select-mapping.phtml b/view/csv-import/admin/mapping-model/select-mapping-model.phtml similarity index 64% rename from view/csv-import/admin/mapping/select-mapping.phtml rename to view/csv-import/admin/mapping-model/select-mapping-model.phtml index 2b795502..f513d01d 100644 --- a/view/csv-import/admin/mapping/select-mapping.phtml +++ b/view/csv-import/admin/mapping-model/select-mapping-model.phtml @@ -1,6 +1,6 @@ prepare(); ?> -pageTitle($this->translate('Select mapping'), 3); ?> +pageTitle($this->translate('Select mapping model'), 3); ?> form()->openTag($form); ?> @@ -8,7 +8,7 @@
    diff --git a/view/csv-import/admin/mapping/show.phtml b/view/csv-import/admin/mapping-model/show.phtml similarity index 98% rename from view/csv-import/admin/mapping/show.phtml rename to view/csv-import/admin/mapping-model/show.phtml index 962fec38..d7948293 100644 --- a/view/csv-import/admin/mapping/show.phtml +++ b/view/csv-import/admin/mapping-model/show.phtml @@ -8,7 +8,7 @@ $this->headLink()->appendStylesheet($this->assetUrl('css/csvimport.css', 'CSVImp translate("Column"); ?> - translate("Mappings"); ?> + translate("Mapping"); ?> translate("Options"); ?> diff --git a/view/csv-import/index/map.phtml b/view/csv-import/index/map.phtml index 11a995af..f9837759 100644 --- a/view/csv-import/index/map.phtml +++ b/view/csv-import/index/map.phtml @@ -66,18 +66,18 @@ $pageTitle = isset($resourceTypeLabels[$resourceType]) '', '#', [ - 'data-sidebar-content-url' => $this->url('admin/csvimport/mapping', + 'data-sidebar-content-url' => $this->url('admin/csvimport/mapping-model', [ - 'controller' => 'Mapping', - 'action' => 'selectMapping', + 'controller' => 'MappingModel', + 'action' => 'selectMappingModel', ] ), 'class' => 'o-icon-menu sidebar-content', - 'title' => $this->translate('Select mapping'), + 'title' => $this->translate('Select mapping model'), 'data-sidebar-selector' => '#sidebar', ] ); ?> - translate('Load a saved mapping'); ?> + translate('Load a saved mapping model'); ?>
  • diff --git a/view/csv-import/index/past-imports.phtml b/view/csv-import/index/past-imports.phtml index 8ebe6e9a..9600a0e9 100644 --- a/view/csv-import/index/past-imports.phtml +++ b/view/csv-import/index/past-imports.phtml @@ -111,9 +111,9 @@ $this->headLink()->appendStylesheet($this->assetUrl('css/csvimport.css', 'CSVImp '#', [ 'data-sidebar-content-url' => $this->url( - 'admin/csvimport/mapping', + 'admin/csvimport/mapping-model', [ - 'controller' => 'Mapping', + 'controller' => 'MappingModel', 'action' => 'save', ], [