From c12212bd684577be729d60db6783dab5461acfb2 Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 2 Dec 2019 00:00:00 +0100 Subject: [PATCH 1/4] Added a way to create linked resources (fix #162). --- config/module.config.php | 5 ++++ src/Form/MappingForm.php | 18 +++++++++++++++ src/Job/Import.php | 8 ++----- src/Mapping/AbstractMapping.php | 2 +- src/Mapping/PropertyMapping.php | 41 ++++++++++++++++++++++++++++++++- 5 files changed, 66 insertions(+), 8 deletions(-) diff --git a/config/module.config.php b/config/module.config.php index f03154dd..d9cc8e84 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -178,6 +178,10 @@ 'label' => 'Omeka resource (by ID)', // @translate 'adapter' => 'resource', ], + 'resource_by_property' => [ + 'label' => 'Omeka resource (by property)', // @translate + 'adapter' => 'resource', + ], ], 'media_ingester_adapter' => [ 'url' => MediaIngesterAdapter\UrlMediaIngesterAdapter::class, @@ -192,6 +196,7 @@ 'csv_import_multivalue_separator' => ',', 'csv_import_rows_by_batch' => 20, 'csv_import_global_language' => '', + 'csv_import_property_identifier' => 'dcterms:identifier', 'csv_import_identifier_property' => '', 'csv_import_automap_check_names_alone' => false, ], diff --git a/src/Form/MappingForm.php b/src/Form/MappingForm.php index 52fbc786..3ace4a1a 100644 --- a/src/Form/MappingForm.php +++ b/src/Form/MappingForm.php @@ -265,6 +265,24 @@ public function init() ], ]); + $basicSettingsFieldset->add([ + 'name' => 'property_identifier', + 'type' => PropertySelect::class, + 'options' => [ + 'label' => 'Property used as identifier of linked resources', // @translate + 'info' => 'Allows to create a link to the resources identified by the values in a cell.', // @translate + 'empty_option' => 'Select below', // @translate + 'term_as_value' => true, + ], + 'attributes' => [ + 'value' => $userSettings->get( + 'csv_import_property_identifier', + $default['csv_import_property_identifier']), + 'class' => 'chosen-select', + 'data-placeholder' => 'Select a property', // @translate + ], + ]); + $this->add([ 'type' => 'fieldset', 'name' => 'advanced-settings', diff --git a/src/Job/Import.php b/src/Job/Import.php index a36cecbf..afd372fd 100644 --- a/src/Job/Import.php +++ b/src/Job/Import.php @@ -170,12 +170,8 @@ public function perform() $this->rowsByBatch = (int) $args['rows_by_batch']; } - // The core allows batch processes only for creation and deletion. - if (!in_array($args['action'], [self::ACTION_CREATE, self::ACTION_DELETE, self::ACTION_SKIP]) - // It allows to identify resources too, so to use a new resource - // from a previous row. - || ($args['action'] === self::ACTION_CREATE && $this->resourceType === 'resources') - ) { + // The core allows batch processes only for deletion. + if (!in_array($args['action'], [self::ACTION_DELETE, self::ACTION_SKIP])) { $this->rowsByBatch = 1; } diff --git a/src/Mapping/AbstractMapping.php b/src/Mapping/AbstractMapping.php index 8c31111b..c11a512b 100644 --- a/src/Mapping/AbstractMapping.php +++ b/src/Mapping/AbstractMapping.php @@ -57,7 +57,7 @@ public function init(array $args, ServiceLocatorInterface $serviceLocator) $this->args = $args; $this->serviceLocator = $serviceLocator; $this->logger = $serviceLocator->get('Omeka\Logger'); - $this->api = $serviceLocator->get('Omeka\ApiManager'); + $this->api = $serviceLocator->get('ControllerPluginManager')->get('api'); } public function getServiceLocator() diff --git a/src/Mapping/PropertyMapping.php b/src/Mapping/PropertyMapping.php index 4278a68c..2fc03083 100644 --- a/src/Mapping/PropertyMapping.php +++ b/src/Mapping/PropertyMapping.php @@ -1,6 +1,8 @@ csvPropertySelector($view->translate('Properties'), false); } + public function init(array $args, ServiceLocatorInterface $serviceLocator) + { + parent::init($args, $serviceLocator); + $this->findResourceFromIdentifier = $serviceLocator->get('ControllerPluginManager') + ->get('findResourceFromIdentifier'); + + // The main identifier property may be used as term or as id in some + // places, so prepare it one time only. + $propertyIdentifier = $this->args['property_identifier']; + if (is_numeric($propertyIdentifier)) { + $this->propertyIdentifier = (int) $propertyIdentifier; + } else { + $property = $this->api->searchOne('properties', ['term' => $propertyIdentifier])->getContent(); + $this->propertyIdentifier = $property + ? $property->id() + : null; + } + } + public function processRow(array $row) { // Reset the data and the map between rows. @@ -46,6 +77,7 @@ public function processRow(array $row) } $dataTypeAdapters = $this->getDataTypeAdapters(); + $findResourceFromIdentifier = $this->findResourceFromIdentifier; // Get default option values. $globalLanguage = isset($this->args['global_language']) ? $this->args['global_language'] : ''; @@ -98,10 +130,17 @@ public function processRow(array $row) break; case 'resource': + if ($type === 'resource_by_property' && $this->propertyIdentifier) { + $linkedResource = $findResourceFromIdentifier($value, $this->propertyIdentifier); + if (!$linkedResource) { + break; + } + $value = $linkedResource; + } $valueData = [ 'value_resource_id' => $value, 'property_id' => $propertyId, - 'type' => $type, + 'type' => $typeAdapter, ]; break; From 365f8cc20d98b764f13a28a5f7777aaf8030703a Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 2 Dec 2019 00:00:00 +0100 Subject: [PATCH 2/4] Merged the two options to set the datatype "resource". --- config/module.config.php | 6 +---- src/Mapping/PropertyMapping.php | 41 +++++++++++++++++++-------------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/config/module.config.php b/config/module.config.php index d9cc8e84..501d1ae5 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -175,11 +175,7 @@ 'adapter' => 'uri', ], 'resource' => [ - 'label' => 'Omeka resource (by ID)', // @translate - 'adapter' => 'resource', - ], - 'resource_by_property' => [ - 'label' => 'Omeka resource (by property)', // @translate + 'label' => 'Omeka resource', // @translate 'adapter' => 'resource', ], ], diff --git a/src/Mapping/PropertyMapping.php b/src/Mapping/PropertyMapping.php index 2fc03083..ef656605 100644 --- a/src/Mapping/PropertyMapping.php +++ b/src/Mapping/PropertyMapping.php @@ -2,6 +2,7 @@ namespace CSVImport\Mapping; use CSVImport\Mvc\Controller\Plugin\FindResourcesFromIdentifiers; +use Omeka\Stdlib\Message; use Zend\ServiceManager\ServiceLocatorInterface; use Zend\View\Renderer\PhpRenderer; @@ -16,7 +17,7 @@ class PropertyMapping extends AbstractMapping protected $findResourceFromIdentifier; /** - * @var int + * @var int|string */ protected $propertyIdentifier; @@ -33,14 +34,14 @@ public function init(array $args, ServiceLocatorInterface $serviceLocator) // The main identifier property may be used as term or as id in some // places, so prepare it one time only. - $propertyIdentifier = $this->args['property_identifier']; - if (is_numeric($propertyIdentifier)) { - $this->propertyIdentifier = (int) $propertyIdentifier; + if (empty($args['property_identifier']) || $args['property_identifier'] === 'o:id') { + $this->propertyIdentifier = 'o:id'; + } elseif (is_numeric($args['property_identifier'])) { + $this->propertyIdentifier = (int) $args['property_identifier']; } else { - $property = $this->api->searchOne('properties', ['term' => $propertyIdentifier])->getContent(); - $this->propertyIdentifier = $property - ? $property->id() - : null; + $result = $this->api + ->searchOne('properties', ['term' => $args['property_identifier']])->getContent(); + $this->propertyIdentifier = $result ? $result->id() : 'o:id'; } } @@ -130,17 +131,11 @@ public function processRow(array $row) break; case 'resource': - if ($type === 'resource_by_property' && $this->propertyIdentifier) { - $linkedResource = $findResourceFromIdentifier($value, $this->propertyIdentifier); - if (!$linkedResource) { - break; - } - $value = $linkedResource; - } + $identifier = $this->findResource($value, $this->propertyIdentifier); $valueData = [ - 'value_resource_id' => $value, + 'value_resource_id' => $identifier, 'property_id' => $propertyId, - 'type' => $typeAdapter, + 'type' => $type, ]; break; @@ -187,4 +182,16 @@ protected function getDataTypeAdapters() } return $dataTypeAdapters; } + + protected function findResource($identifier, $propertyIdentifier = 'o:id') + { + $resourceType = $this->args['resource_type']; + $findResourceFromIdentifier = $this->findResourceFromIdentifier; + $resourceId = $findResourceFromIdentifier($identifier, $propertyIdentifier, $resourceType); + if (empty($resourceId)) { + $this->setHasErr(true); + return false; + } + return $resourceId; + } } From e6e06a15db6add7ae760412172cf95fef7fbdd21 Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 2 Dec 2019 00:00:00 +0100 Subject: [PATCH 3/4] Added a message when an identifier is not identified. --- src/Mapping/PropertyMapping.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mapping/PropertyMapping.php b/src/Mapping/PropertyMapping.php index ef656605..734e0c69 100644 --- a/src/Mapping/PropertyMapping.php +++ b/src/Mapping/PropertyMapping.php @@ -189,6 +189,8 @@ protected function findResource($identifier, $propertyIdentifier = 'o:id') $findResourceFromIdentifier = $this->findResourceFromIdentifier; $resourceId = $findResourceFromIdentifier($identifier, $propertyIdentifier, $resourceType); if (empty($resourceId)) { + $this->logger->err(new Message('"%s" (%s) is not a valid resource identifier.', // @translate + $identifier, $propertyIdentifier)); $this->setHasErr(true); return false; } From 6910447000ef4f6579178bbd92b57ec07ce83eff Mon Sep 17 00:00:00 2001 From: Daniel Berthereau Date: Mon, 2 Dec 2019 00:00:00 +0100 Subject: [PATCH 4/4] Merged the settings "property_identifier" and "identifier_property". --- config/module.config.php | 3 +-- src/Form/MappingForm.php | 34 ++++++++------------------------- src/Job/Import.php | 2 +- src/Mapping/PropertyMapping.php | 12 ++++++------ 4 files changed, 16 insertions(+), 35 deletions(-) diff --git a/config/module.config.php b/config/module.config.php index 501d1ae5..fa1eb3ef 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -192,8 +192,7 @@ 'csv_import_multivalue_separator' => ',', 'csv_import_rows_by_batch' => 20, 'csv_import_global_language' => '', - 'csv_import_property_identifier' => 'dcterms:identifier', - 'csv_import_identifier_property' => '', + 'csv_import_identifier_property' => 'dcterms:identifier', 'csv_import_automap_check_names_alone' => false, ], ], diff --git a/src/Form/MappingForm.php b/src/Form/MappingForm.php index 3ace4a1a..d74b597f 100644 --- a/src/Form/MappingForm.php +++ b/src/Form/MappingForm.php @@ -266,18 +266,21 @@ public function init() ]); $basicSettingsFieldset->add([ - 'name' => 'property_identifier', + 'name' => 'identifier_property', 'type' => PropertySelect::class, 'options' => [ - 'label' => 'Property used as identifier of linked resources', // @translate - 'info' => 'Allows to create a link to the resources identified by the values in a cell.', // @translate + 'label' => 'Resource identifier property', // @translate + 'info' => 'Use this property, generally "dcterms:identifier", to identify the existing resources to link or to get. In all cases, it is strongly recommended to add one or more unique identifiers to all your resources.', // @translate 'empty_option' => 'Select below', // @translate + 'prepend_value_options' => [ + 'internal_id' => 'Internal ID', // @translate + ], 'term_as_value' => true, ], 'attributes' => [ 'value' => $userSettings->get( - 'csv_import_property_identifier', - $default['csv_import_property_identifier']), + 'csv_import_identifier_property', + $default['csv_import_identifier_property']), 'class' => 'chosen-select', 'data-placeholder' => 'Select a property', // @translate ], @@ -337,27 +340,6 @@ public function init() ]); } - $advancedSettingsFieldset->add([ - 'name' => 'identifier_property', - 'type' => PropertySelect::class, - 'options' => [ - 'label' => 'Resource identifier property', // @translate - 'info' => 'Use this property, generally "dcterms:identifier", to identify the existing resources, so it will be possible to update them. One column of the file must map the selected property. In all cases, it is strongly recommended to add one ore more unique identifiers to all your resources.', // @translate - 'empty_option' => 'Select below', // @translate - 'prepend_value_options' => [ - 'internal_id' => 'Internal ID', // @translate - ], - 'term_as_value' => true, - ], - 'attributes' => [ - 'value' => $userSettings->get( - 'csv_import_identifier_property', - $default['csv_import_identifier_property']), - 'class' => 'action-option chosen-select', - 'data-placeholder' => 'Select a property', // @translate - ], - ]); - $advancedSettingsFieldset->add([ 'name' => 'action_unidentified', 'type' => 'radio', diff --git a/src/Job/Import.php b/src/Job/Import.php index afd372fd..aedbc2d2 100644 --- a/src/Job/Import.php +++ b/src/Job/Import.php @@ -157,7 +157,7 @@ public function perform() // The main identifier property may be used as term or as id in some // places, so prepare it one time only. if (empty($args['identifier_property']) || $args['identifier_property'] === 'internal_id') { - $this->identifierPropertyId = $args['identifier_property']; + $this->identifierPropertyId = 'internal_id'; } elseif (is_numeric($args['identifier_property'])) { $this->identifierPropertyId = (int) $args['identifier_property']; } else { diff --git a/src/Mapping/PropertyMapping.php b/src/Mapping/PropertyMapping.php index 734e0c69..36b8cad4 100644 --- a/src/Mapping/PropertyMapping.php +++ b/src/Mapping/PropertyMapping.php @@ -34,14 +34,14 @@ public function init(array $args, ServiceLocatorInterface $serviceLocator) // The main identifier property may be used as term or as id in some // places, so prepare it one time only. - if (empty($args['property_identifier']) || $args['property_identifier'] === 'o:id') { - $this->propertyIdentifier = 'o:id'; - } elseif (is_numeric($args['property_identifier'])) { - $this->propertyIdentifier = (int) $args['property_identifier']; + if (empty($args['identifier_property']) || $args['identifier_property'] === 'internal_id') { + $this->propertyIdentifier = 'internal_id'; + } elseif (is_numeric($args['identifier_property'])) { + $this->propertyIdentifier = (int) $args['identifier_property']; } else { $result = $this->api - ->searchOne('properties', ['term' => $args['property_identifier']])->getContent(); - $this->propertyIdentifier = $result ? $result->id() : 'o:id'; + ->searchOne('properties', ['term' => $args['identifier_property']])->getContent(); + $this->propertyIdentifier = $result ? $result->id() : 'internal_id'; } }