Skip to content

Commit a336770

Browse files
committed
Merge branch 'dataverse_required_metadata-862' into 'main'
Add support for custom required metadata blocks fields See merge request softwares-pkp/plugins_ojs/dataverse!216
2 parents 5eb4a37 + ac76800 commit a336770

18 files changed

Lines changed: 1479 additions & 14 deletions

DataverseSettingsForm.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
use PKP\form\Form;
66
use PKP\plugins\Plugin;
77
use APP\core\Application;
8+
use PKP\cache\CacheManager;
9+
use PKP\cache\FileCache;
810
use APP\template\TemplateManager;
911
use PKP\db\DAORegistry;
1012
use PKP\form\validation\FormValidatorUrl;
@@ -110,6 +112,7 @@ public function execute(...$functionArgs)
110112
foreach (self::CONFIG_VARS as $configVar => $type) {
111113
$this->plugin->updateSetting($this->contextId, $configVar, $this->getData($configVar), $type);
112114
}
115+
$this->flushCache();
113116
parent::execute(...$functionArgs);
114117
}
115118

@@ -155,4 +158,24 @@ private function encryptApiToken(): void
155158
$this->setData('apiToken', $encryptedToken);
156159
}
157160
}
161+
162+
private function flushCache(): void
163+
{
164+
$cache = $this->getCache('dataverse_required_metadata');
165+
$cache->flush();
166+
}
167+
168+
private function getCache(string $cacheId)
169+
{
170+
$cacheManager = CacheManager::getManager();
171+
$cache = $cacheManager->getFileCache(
172+
$this->contextId,
173+
$cacheId,
174+
function (FileCache $cache) {
175+
$cache->setEntireCache([]);
176+
return [];
177+
}
178+
);
179+
return $cache;
180+
}
158181
}

api/v1/datasets/DatasetHandler.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,23 @@ public function addDataset($slimRequest, $response, $args)
229229
$dataset->setSubject($requestParams['datasetSubject']);
230230
$dataset->setLicense($requestParams['datasetLicense']);
231231

232+
$excludedKeys = [
233+
'datasetTitle',
234+
'datasetDescription',
235+
'datasetKeywords',
236+
'datasetSubject',
237+
'datasetLicense'
238+
];
239+
240+
foreach ($requestParams as $key => $value) {
241+
if (in_array($key, $excludedKeys)) {
242+
continue;
243+
}
244+
$metadataName = str_replace('dataset', '', $key);
245+
$metadataName = $metadataName === strtoupper($metadataName) ? $metadataName : lcfirst($metadataName);
246+
$dataset->setData($metadataName, $value);
247+
}
248+
232249
if (!empty($dataset->getFiles())) {
233250
$datasetService = new DatasetService();
234251
$depositInfo = $datasetService->deposit($submission, $dataset);

classes/components/forms/DatasetMetadataForm.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
use PKP\components\forms\FieldRichTextarea;
88
use PKP\components\forms\FieldControlledVocab;
99
use PKP\components\forms\FieldSelect;
10+
use PKP\components\forms\FieldTextarea;
1011
use APP\core\Application;
1112
use PKP\facades\Locale;
1213
use APP\plugins\generic\dataverse\classes\DataverseMetadata;
14+
use APP\plugins\generic\dataverse\dataverseAPI\DataverseClient;
1315

1416
class DatasetMetadataForm extends FormComponent
1517
{
@@ -70,6 +72,66 @@ public function __construct($action, $method, $dataset, $page)
7072
'options' => $this->mapLicensesForDisplay($dataverseLicenses),
7173
'value' => $datasetMetadata['license'],
7274
]));
75+
76+
try {
77+
$flattenedFields = $this->getFlattenedRequiredMetadataFields();
78+
foreach ($flattenedFields as $field) {
79+
$this->addMetadataField($field, $dataset);
80+
}
81+
} catch (DataverseException $e) {
82+
error_log('Error getting required metadata fields: ' . $e->getMessage());
83+
}
84+
}
85+
86+
private function addMetadataField($field, $dataset): void
87+
{
88+
$fieldName = 'dataset' . ucfirst($field['name']);
89+
$fieldType = $this->getFieldType($field);
90+
91+
$fieldConfig = $this->buildFieldConfig($field, $dataset);
92+
93+
$this->addField(new $fieldType($fieldName, $fieldConfig));
94+
}
95+
96+
private function buildFieldConfig($field, $dataset): array
97+
{
98+
$config = [
99+
'label' => $field['displayName'],
100+
'description' => $field['description'],
101+
'isRequired' => $field['isRequired'],
102+
'value' => isset($dataset) ? $dataset->getData($field['name']) : ''
103+
];
104+
105+
if (!empty($field['isControlledVocabulary'])) {
106+
$config['options'] = $this->mapControlledVocabularyOptions($field['controlledVocabularyValues']);
107+
}
108+
109+
return $config;
110+
}
111+
112+
private function mapControlledVocabularyOptions(array $values): array
113+
{
114+
return array_map(
115+
static fn ($value) => ['label' => $value, 'value' => $value],
116+
$values
117+
);
118+
}
119+
120+
private function getFieldType($field): string
121+
{
122+
if (!empty($field['isControlledVocabulary'])) {
123+
return FieldSelect::class;
124+
}
125+
126+
$fieldTypes = [
127+
'TEXT' => FieldText::class,
128+
'EMAIL' => FieldText::class,
129+
'DATE' => FieldText::class,
130+
'URL' => FieldText::class,
131+
'TEXTBOX' => FieldTextarea::class
132+
];
133+
134+
return $fieldTypes[$field['type']] ?? FieldText::class;
73135
}
74136

75137
private function getDatasetMetadata($dataset)
@@ -129,4 +191,13 @@ public function getConfig()
129191

130192
return $config;
131193
}
194+
195+
private function getFlattenedRequiredMetadataFields(): array
196+
{
197+
$dataverseClient = new DataverseClient();
198+
$dataverseCollectionActions = $dataverseClient->getDataverseCollectionActions();
199+
$requiredMetadata = $dataverseCollectionActions->getRequiredMetadata();
200+
201+
return $dataverseCollectionActions->getFlattenedFields($requiredMetadata);
202+
}
132203
}

classes/dispatchers/DatasetMetadataDispatcher.php

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
use APP\plugins\generic\dataverse\classes\entities\Dataset;
1111
use APP\plugins\generic\dataverse\classes\components\forms\DatasetMetadataForm;
1212
use APP\plugins\generic\dataverse\classes\services\DataStatementService;
13+
use APP\plugins\generic\dataverse\dataverseAPI\DataverseClient;
14+
use PKP\validation\ValidatorFactory;
1315

1416
class DatasetMetadataDispatcher extends DataverseDispatcher
1517
{
@@ -43,6 +45,17 @@ public function addToEditorsStep(string $hookName, array $params)
4345
$dataset = new Dataset();
4446
$dataset->setData('subject', $submission->getData('datasetSubject'));
4547
$dataset->setData('license', $submission->getData('datasetLicense'));
48+
49+
try {
50+
$flattenedFields = $this->getFlattenedRequiredMetadataFields();
51+
foreach ($flattenedFields as $field) {
52+
$metadataName = 'dataset' . ucfirst($field['name']);
53+
$dataset->setData($field['name'], $submission->getData($metadataName));
54+
}
55+
} catch (DataverseException $e) {
56+
error_log('Error getting metadata fields from submission: ' . $e->getMessage());
57+
}
58+
4659
$datasetMetadataForm = new DatasetMetadataForm($submissionApiUrl, 'POST', $dataset, 'submission');
4760

4861
$steps = $templateMgr->getState('steps');
@@ -70,6 +83,13 @@ public function addToReviewStep(string $hookName, array $params): bool
7083
$templateMgr = $params[1];
7184
$output = &$params[2];
7285

86+
try {
87+
$flattenedFields = $this->getFlattenedRequiredMetadataFields();
88+
$templateMgr->assign('requiredMetadataFields', $flattenedFields);
89+
} catch (DataverseException $e) {
90+
error_log('Error getting required metadata fields: ' . $e->getMessage());
91+
}
92+
7393
if ($step === 'editors') {
7494
$output .= $templateMgr->fetch($this->plugin->getTemplateResource('review/datasetMetadata.tpl'));
7595
}
@@ -86,14 +106,84 @@ public function validateSubmissionFields(string $hookName, array $params)
86106
$dataStatementTypes = $publication->getData('dataStatementTypes');
87107

88108
if (
89-
!empty($dataStatementTypes)
90-
&& in_array(DataStatementService::DATA_STATEMENT_TYPE_DATAVERSE_SUBMITTED, $dataStatementTypes)
109+
empty($dataStatementTypes)
110+
|| !in_array(DataStatementService::DATA_STATEMENT_TYPE_DATAVERSE_SUBMITTED, $dataStatementTypes)
91111
) {
92-
if (!$submission->getData('datasetSubject')) {
93-
$errors['datasetSubject'] = [__('plugins.generic.dataverse.error.datasetSubject.required')];
112+
return false;
113+
}
114+
115+
if (!$submission->getData('datasetSubject')) {
116+
$errors['datasetSubject'] = [__('plugins.generic.dataverse.error.datasetSubject.required')];
117+
}
118+
119+
try {
120+
$flattenedFields = $this->getFlattenedRequiredMetadataFields();
121+
foreach ($flattenedFields as $field) {
122+
$metadataName = 'dataset' . ucfirst($field['name']);
123+
$value = $submission->getData($metadataName);
124+
125+
if (empty($value)) {
126+
$errors[$metadataName] = [__('validator.required')];
127+
continue;
128+
}
129+
130+
$this->validateFieldByType($field, $metadataName, $value, $errors);
94131
}
132+
} catch (DataverseException $e) {
133+
error_log('Error getting required metadata fields: ' . $e->getMessage());
95134
}
96135

97136
return false;
98137
}
138+
139+
private function validateFieldByType(array $field, string $metadataName, $value, array &$errors): void
140+
{
141+
$validationRules = $this->getValidationRules($field['type']);
142+
143+
if (empty($validationRules)) {
144+
return;
145+
}
146+
147+
$validator = ValidatorFactory::make(
148+
['value' => $value],
149+
['value' => $validationRules['rules']]
150+
);
151+
152+
if (!$validator->passes()) {
153+
$errors[$metadataName] = $validationRules['useValidatorMessages']
154+
? $validator->errors()->getMessages()['value']
155+
: [__($validationRules['errorKey'])];
156+
}
157+
}
158+
159+
private function getValidationRules(string $type): array
160+
{
161+
$rules = [
162+
'DATE' => [
163+
'rules' => ['required', 'date', 'date_format:Y-m-d'],
164+
'useValidatorMessages' => true,
165+
],
166+
'URL' => [
167+
'rules' => ['required', 'url'],
168+
'errorKey' => 'validator.url',
169+
'useValidatorMessages' => false,
170+
],
171+
'EMAIL' => [
172+
'rules' => ['required', 'email_or_localhost'],
173+
'errorKey' => 'validator.email',
174+
'useValidatorMessages' => false,
175+
],
176+
];
177+
178+
return $rules[$type] ?? [];
179+
}
180+
181+
private function getFlattenedRequiredMetadataFields(): array
182+
{
183+
$dataverseClient = new DataverseClient();
184+
$dataverseCollectionActions = $dataverseClient->getDataverseCollectionActions();
185+
$requiredMetadata = $dataverseCollectionActions->getRequiredMetadata();
186+
187+
return $dataverseCollectionActions->getFlattenedFields($requiredMetadata);
188+
}
99189
}

classes/dispatchers/DataverseEventsDispatcher.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,22 @@ public function modifySubmissionSchema(string $hookName, array $params): bool
6262
]
6363
];
6464

65+
try {
66+
$dataverseClient = new DataverseClient();
67+
$dataverseCollectionActions = $dataverseClient->getDataverseCollectionActions();
68+
$requiredMetadata = $dataverseCollectionActions->getRequiredMetadata();
69+
$metadataFields = $dataverseCollectionActions->getFlattenedFields($requiredMetadata);
70+
foreach ($metadataFields as $field) {
71+
$schema->properties->{'dataset' . ucfirst($field['name'])} = (object) [
72+
'type' => 'string',
73+
'apiSummary' => true,
74+
'validation' => ['nullable'],
75+
];
76+
}
77+
} catch (DataverseException $e) {
78+
error_log('Dataverse Error while modifying submission schema: ' . $e->getMessage());
79+
}
80+
6581
return false;
6682
}
6783

classes/factories/JsonDatasetFactory.php

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,18 @@
77
use APP\plugins\generic\dataverse\classes\entities\DatasetContact;
88
use APP\plugins\generic\dataverse\classes\entities\DatasetFile;
99
use APP\plugins\generic\dataverse\classes\entities\DatasetRelatedPublication;
10+
use APP\plugins\generic\dataverse\dataverseAPI\DataverseClient;
1011
use stdClass;
1112

1213
class JsonDatasetFactory extends DatasetFactory
1314
{
1415
private $jsonContent;
16+
private $dataverseClient;
1517

16-
public function __construct(string $jsonContent)
18+
public function __construct(string $jsonContent, ?DataverseClient $dataverseClient = null)
1719
{
1820
$this->jsonContent = $jsonContent;
21+
$this->dataverseClient = $dataverseClient;
1922
}
2023

2124
private function getCurrentDatasetVersion()
@@ -131,6 +134,64 @@ protected function sanitizeProps(): array
131134
return $datasetFile;
132135
}, $datasetVersion->files);
133136

137+
$props = $this->sanitizeAdditionalProps($props, $datasetVersion->metadataBlocks);
138+
139+
return $props;
140+
}
141+
142+
private function sanitizeAdditionalProps(array $props, stdClass $metadataBlocks): array
143+
{
144+
$requiredMetadata = $this->getAdditionalRequiredMetadata();
145+
146+
foreach ($requiredMetadata as $block) {
147+
if (!isset($metadataBlocks->{$block['name']})) {
148+
continue;
149+
}
150+
151+
foreach ($block['fields'] as $field) {
152+
$metadataBlockField = $this->findMetadataField($metadataBlocks->{$block['name']}->fields, $field['name']);
153+
154+
if (!$metadataBlockField) {
155+
continue;
156+
}
157+
158+
$fieldValue = $field['multiple']
159+
? array_shift($metadataBlockField->value)
160+
: $metadataBlockField->value;
161+
162+
$props = $this->extractFieldValues($props, $field, $fieldValue);
163+
}
164+
}
165+
134166
return $props;
135167
}
168+
169+
private function findMetadataField(array $fields, string $fieldName): ?stdClass
170+
{
171+
foreach ($fields as $field) {
172+
if ($field->typeName === $fieldName) {
173+
return $field;
174+
}
175+
}
176+
return null;
177+
}
178+
179+
private function extractFieldValues(array $props, array $field, $fieldValue): array
180+
{
181+
if (isset($field['childFields'])) {
182+
foreach ($field['childFields'] as $childField) {
183+
$props[$childField['name']] = $fieldValue->{$childField['name']}->value ?? null;
184+
}
185+
} else {
186+
$props[$field['name']] = $fieldValue;
187+
}
188+
189+
return $props;
190+
}
191+
192+
private function getAdditionalRequiredMetadata(): array
193+
{
194+
$dataverseClient = $this->dataverseClient ?? new DataverseClient();
195+
return $dataverseClient->getDataverseCollectionActions()->getRequiredMetadata();
196+
}
136197
}

0 commit comments

Comments
 (0)