diff --git a/src/Controller/AdminPages/BaseAdminController.php b/src/Controller/AdminPages/BaseAdminController.php index 92d5dd5d..2619f9f5 100644 --- a/src/Controller/AdminPages/BaseAdminController.php +++ b/src/Controller/AdminPages/BaseAdminController.php @@ -58,6 +58,7 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; +use Symfony\Component\Serializer\Exception\UnexpectedValueException; use Symfony\Component\Validator\ConstraintViolationList; use Symfony\Contracts\Translation\TranslatorInterface; @@ -338,17 +339,33 @@ abstract class BaseAdminController extends AbstractController $file = $import_form['file']->getData(); $data = $import_form->getData(); + if ($data['format'] === 'auto') { + $format = $importer->determineFormat($file->getClientOriginalExtension()); + if (null === $format) { + $this->addFlash('error', 'parts.import.flash.error.unknown_format'); + goto ret; + } + } else { + $format = $data['format']; + } + $options = [ 'parent' => $data['parent'], 'preserve_children' => $data['preserve_children'], - 'format' => $data['format'], + 'format' => $format, 'class' => $this->entity_class, 'csv_delimiter' => $data['csv_delimiter'], ]; $this->commentHelper->setMessage('Import '.$file->getClientOriginalName()); - $errors = $importer->importFileAndPersistToDB($file, $options); + try { + $errors = $importer->importFileAndPersistToDB($file, $options); + } + catch (UnexpectedValueException $e) { + $this->addFlash('error', 'parts.import.flash.error.invalid_file'); + goto ret; + } foreach ($errors as $name => $error) { /** @var ConstraintViolationList $error */ @@ -383,6 +400,7 @@ abstract class BaseAdminController extends AbstractController $em->flush(); } + ret: return $this->renderForm($this->twig_template, [ 'entity' => $new_entity, 'form' => $form, diff --git a/src/Controller/PartImportExportController.php b/src/Controller/PartImportExportController.php index 9abf88d2..4d4aa54c 100644 --- a/src/Controller/PartImportExportController.php +++ b/src/Controller/PartImportExportController.php @@ -33,7 +33,7 @@ use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Validator\ConstraintViolationList; +use UnexpectedValueException; class PartImportExportController extends AbstractController { @@ -64,9 +64,19 @@ class PartImportExportController extends AbstractController $file = $import_form['file']->getData(); $data = $import_form->getData(); + if ($data['format'] === 'auto') { + $format = $this->entityImporter->determineFormat($file->getClientOriginalExtension()); + if (null === $format) { + $this->addFlash('error', 'parts.import.flash.error.unknown_format'); + goto ret; + } + } else { + $format = $data['format']; + } + $options = [ 'preserve_children' => $data['preserve_children'], - 'format' => $data['format'], + 'format' => $format, 'part_category' => $data['part_category'], 'class' => Part::class, 'csv_delimiter' => $data['csv_delimiter'], @@ -76,7 +86,12 @@ class PartImportExportController extends AbstractController $entities = []; - $errors = $this->entityImporter->importFileAndPersistToDB($file, $options, $entities); + try { + $errors = $this->entityImporter->importFileAndPersistToDB($file, $options, $entities); + } catch (UnexpectedValueException $e) { + $this->addFlash('error', 'parts.import.flash.error.invalid_file'); + goto ret; + } if ($errors) { $this->addFlash('error', 'parts.import.flash.error'); @@ -85,6 +100,8 @@ class PartImportExportController extends AbstractController } } + + ret: return $this->renderForm('parts/import/parts_import.html.twig', [ 'import_form' => $import_form, 'imported_entities' => $entities ?? [], diff --git a/src/Form/AdminPages/ImportType.php b/src/Form/AdminPages/ImportType.php index 71e088a3..ba0c7db7 100644 --- a/src/Form/AdminPages/ImportType.php +++ b/src/Form/AdminPages/ImportType.php @@ -57,6 +57,7 @@ class ImportType extends AbstractType ->add('format', ChoiceType::class, [ 'choices' => [ + 'parts.import.format.auto' => 'auto', 'JSON' => 'json', 'XML' => 'xml', 'CSV' => 'csv', diff --git a/src/Services/ImportExportSystem/EntityImporter.php b/src/Services/ImportExportSystem/EntityImporter.php index a6d82daa..25e4338b 100644 --- a/src/Services/ImportExportSystem/EntityImporter.php +++ b/src/Services/ImportExportSystem/EntityImporter.php @@ -279,6 +279,33 @@ class EntityImporter return $this->importString($file->getContent(), $options, $errors); } + + /** + * Determines the format to import based on the file extension. + * @param string $extension The file extension to use + * @return string The format to use (json, xml, csv, yaml), or null if the extension is unknown + */ + public function determineFormat(string $extension): ?string + { + //Convert the extension to lower case + $extension = strtolower($extension); + + switch ($extension) { + case 'json': + return 'json'; + case 'xml': + return 'xml'; + case 'csv': + case 'tsv': + return 'csv'; + case 'yaml': + case 'yml': + return 'yaml'; + default: + return null; + } + } + /** * This functions corrects the parent setting based on the children value of the parent. * diff --git a/tests/Services/ImportExportSystem/EntityImporterTest.php b/tests/Services/ImportExportSystem/EntityImporterTest.php index 79599c8e..57f8784e 100644 --- a/tests/Services/ImportExportSystem/EntityImporterTest.php +++ b/tests/Services/ImportExportSystem/EntityImporterTest.php @@ -151,4 +151,24 @@ EOT; $this->assertCount(2, $errors); $this->assertSame('Node 1', $errors[0]['entity']->getName()); } + + public function formatDataProvider(): array + { + return [ + ['csv', 'csv'], + ['csv', 'CSV'], + ['xml', 'Xml'], + ['json', 'json'], + ['yaml', 'yml'], + ['yaml', 'YAML'], + ]; + } + + /** + * @dataProvider formatDataProvider + */ + public function testDetermineFormat(string $expected, string $extension): void + { + $this->assertSame($expected, $this->service->determineFormat($extension)); + } } diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 1f81354d..a7f4bf2d 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -6674,7 +6674,6 @@ If you have done this incorrectly or if a computer is no longer trusted, you can The parent can not be one of the children of itself. - obsolete @@ -11038,5 +11037,23 @@ Element 3 Errors during import. This is most likely caused by some invalid data. + + + parts.import.format.auto + Automatic (based on file extension) + + + + + parts.import.flash.error.unknown_format + Could not determine the format from the given file! + + + + + parts.import.flash.error.invalid_file + File invalid / malformatted. Please check that you have selected the right format! + +