From 1b4d8ec6e43fd2e5f61a35a80e12f9f9a0eba643 Mon Sep 17 00:00:00 2001 From: Rastislav Chynoransky Date: Wed, 11 Dec 2024 18:57:04 +0700 Subject: [PATCH] [import] fix measurement replacements --- app/Enums/FrontendEnum.php | 1 + app/Import.php | 8 ++ app/Importers/UpmImporter.php | 144 ++++++++++++++++++++++++ database/seeders/DatabaseSeeder.php | 1 + database/seeders/ImportsTableSeeder.php | 21 ++++ lang/cs/item.php | 59 +++++----- lang/en/item.php | 59 +++++----- lang/sk/item.php | 59 +++++----- tests/Importers/UpmImporterTest.php | 113 +++++++++++++++++++ 9 files changed, 375 insertions(+), 90 deletions(-) create mode 100644 app/Importers/UpmImporter.php create mode 100644 database/seeders/ImportsTableSeeder.php create mode 100644 tests/Importers/UpmImporterTest.php diff --git a/app/Enums/FrontendEnum.php b/app/Enums/FrontendEnum.php index e5e550622..1f92a3ece 100644 --- a/app/Enums/FrontendEnum.php +++ b/app/Enums/FrontendEnum.php @@ -6,4 +6,5 @@ enum FrontendEnum: string { case WEBUMENIA = 'webumenia'; case MORAVSKA_GALERIE = 'moravska-galerie'; + case UPM = 'upm'; } diff --git a/app/Import.php b/app/Import.php index b6c821708..e65ea7080 100644 --- a/app/Import.php +++ b/app/Import.php @@ -30,6 +30,14 @@ class Import extends Model 'completed_at' => 'datetime', ]; + protected $fillable = [ + 'name', + 'dir_path', + 'iip_dir_path', + 'class_name', + 'disk', + ]; + public function user() { return $this->belongsTo(User::class); diff --git a/app/Importers/UpmImporter.php b/app/Importers/UpmImporter.php new file mode 100644 index 000000000..756c6d7b7 --- /dev/null +++ b/app/Importers/UpmImporter.php @@ -0,0 +1,144 @@ + 'Inventárníčíslo', + 'title:cs' => 'Název', + 'title:sk' => 'Název', + 'title:en' => 'Název EN', + 'dating:cs' => 'Datace', + 'dating:sk' => 'Datace', + 'date_earliest' => 'Od', + 'date_latest' => 'Do', + 'work_type:cs' => 'Výtvarný druh', + 'work_type:sk' => 'Výtvarný druh', + 'object_type:cs' => 'Typ', + 'object_type:sk' => 'Typ', + 'medium:cs' => 'Materiál', + 'medium:sk' => 'Materiál', + 'technique:cs' => 'Technika', + 'technique:sk' => 'Technika', + 'topic:cs' => 'Námět', + 'topic:sk' => 'Námět', + 'inscription:cs' => 'Značení', + 'inscription:sk' => 'Značení', + 'related_work:sk' => 'Sbírka', + 'related_work:cs' => 'Sbírka', + 'acquisition_date' => 'Datum akvizice', + ]; + + protected $defaults = [ + 'relationship_type:sk' => 'zo súboru', + 'relationship_type:cs' => 'ze souboru', + 'relationship_type:en' => 'collection', + 'gallery:cs' => 'Uměleckoprůmyslové museum v Praze, UPM', + 'gallery:sk' => 'Umeleckopriemyselné múzeum v Prahe, UPM', + 'frontends' => [ + FrontendEnum::UPM, + FrontendEnum::WEBUMENIA, + ], + ]; + + protected static $options = [ + 'delimiter' => ';', + 'enclosure' => '"', + 'escape' => '\\', + 'newline' => "\n", + ]; + + protected function init() + { + $this->sanitizers[] = function ($value) { + return empty_to_null(trim($value)); + }; + } + + protected function getItemId(array $record) + { + return 'CZE:UPM.' . str($record['ID']) + ->explode('_') + ->transform(fn ($part) => str($part) + ->replaceMatches('/\W/', '-') + ->trim('-') + ) + ->join('_'); + } + + protected function getItemImageFilenameFormat(array $record): string + { + return str($record['ID']) + ->explode('_') + ->transform(fn ($part) => '0*' . preg_quote($part)) + ->join('_') . '(_.*)?'; + } + + protected function hydrateAuthor(array $record): string + { + $authors = str($record['Autor']); + if ($authors->isEmpty()) { + return 'Neznámý autor'; + } + + return $authors + ->split('/\s*;\s*/') + ->map(function (string $author) { + preg_match('/^(?[^–]*)(\s–\s(?.*))?$/', $author, $matches); + + if (!isset($matches['name'], $matches['role'])) { + return $author; + } + + return sprintf('%s (%s)', formatName($matches['name']), $matches['role']); + }) + ->join('; '); + } + + protected function hydratePlace(array $record, string $locale): ?string + { + if (!in_array($locale, ['cs', 'sk'])) { + return null; + } + + $place = str($record['Vznik'])->match('/^([^;]+)/'); + return $place->isNotEmpty() ? $place->toString() : null; + } + + protected function hydrateAdditionals(array $record, string $locale): ?array + { + if ($locale !== 'cs') { + return null; + } + + $additionals = []; + + if ($record['Způsob akvizice'] !== null) { + $additionals['acquisition'] = $record['Způsob akvizice']; + } + + if ($record['Výstava'] !== null) { + $additionals['exhibition'] = $record['Výstava']; + } + + $producer = str($record['Vznik'])->match('/;(.+)/'); + if ($producer->isNotEmpty()) { + $additionals['producer'] = $producer->toString(); + } + + return $additionals ?: null; + } + + protected function hydrateMeasurement(array $record, $locale): ?string + { + if (empty($record['Rozměry'])) { + return null; + } + + $replacements = trans('item.measurement_replacements', [], $locale); + return strtr($record['Rozměry'], $replacements); + } +} \ No newline at end of file diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 78b93ca72..037ceb127 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -19,6 +19,7 @@ public function run() $this->call(CollectionsTableSeeder::class); $this->call(CategoriesTableSeeder::class); $this->call(ArticlesTableSeeder::class); + $this->call(ImportsTableSeeder::class); // $this->call(SketchbooksTableSeeder::class); } diff --git a/database/seeders/ImportsTableSeeder.php b/database/seeders/ImportsTableSeeder.php new file mode 100644 index 000000000..f0bbc26c0 --- /dev/null +++ b/database/seeders/ImportsTableSeeder.php @@ -0,0 +1,21 @@ + 'UPM', + 'dir_path' => 'UPM', + 'iip_dir_path' => 'UPM', + 'class_name' => UpmImporter::class, + 'disk' => 'import_iip', + ]); + } +} \ No newline at end of file diff --git a/lang/cs/item.php b/lang/cs/item.php index 22b433810..f0c14ec46 100644 --- a/lang/cs/item.php +++ b/lang/cs/item.php @@ -108,36 +108,35 @@ ], ], 'measurement_replacements' => [ - 'a' => 'výška hlavní části', - 'a.' => 'výška hlavní části', - 'b' => 'výška vedlejší části', - 'b.' => 'výška vedlejší části', - 'čas' => 'čas', - 'd' => 'délka', - 'd.' => 'délka', - 'h' => 'hloubka/tloušťka', - 'h.' => 'hloubka/tloušťka', - 'hmot' => 'hmotnost', - 'hmot.' => 'hmotnost', - 'hr' => 'hloubka s rámem', - 'jiný' => 'jiný nespecifikovaný', - 'p' => 'průměr/ráže', - 'p.' => 'průměr/ráže', - 'r.' => 'ráže', - 'ryz' => 'ryzost', - 's' => 'šířka', - 's.' => 'šířka', - 'sd.' => 'šířka grafické desky', - 'sp' => 'šířka s paspartou', - 'sp.' => 'šířka s paspartou', - 'sr' => 'šířka s rámem', - 'v' => 'celková výška/délka', - 'v.' => 'celková výška/délka', - 'vd.' => 'výška grafické desky', - 'vp' => 'výška s paspartou', - 'vp.' => 'výška s paspartou', - 'vr' => 'výška s rámem', - '=' => ' ', + 'a=' => 'výška hlavní části ', + 'a.=' => 'výška hlavní části ', + 'b=' => 'výška vedlejší části ', + 'b.=' => 'výška vedlejší části ', + 'čas=' => 'čas ', + 'd=' => 'délka ', + 'd.=' => 'délka ', + 'h=' => 'hloubka/tloušťka ', + 'h.=' => 'hloubka/tloušťka ', + 'hmot=' => 'hmotnost ', + 'hmot.=' => 'hmotnost ', + 'hr=' => 'hloubka s rámem ', + 'jiný=' => 'jiný nespecifikovaný ', + 'p=' => 'průměr/ráže ', + 'p.=' => 'průměr/ráže ', + 'r.=' => 'ráže ', + 'ryz=' => 'ryzost ', + 's=' => 'šířka ', + 's.=' => 'šířka ', + 'sd.=' => 'šířka grafické desky ', + 'sp=' => 'šířka s paspartou ', + 'sp.=' => 'šířka s paspartou ', + 'sr=' => 'šířka s rámem ', + 'v=' => 'celková výška/délka ', + 'v.=' => 'celková výška/délka ', + 'vd.=' => 'výška grafické desky ', + 'vp=' => 'výška s paspartou ', + 'vp.=' => 'výška s paspartou ', + 'vr=' => 'výška s rámem ', ], 'untitled' => 'bez názvu', 'authority_roles' => [ diff --git a/lang/en/item.php b/lang/en/item.php index 486ab7b7a..ff5404e59 100644 --- a/lang/en/item.php +++ b/lang/en/item.php @@ -105,36 +105,35 @@ ], ], 'measurement_replacements' => [ - 'a' => 'height of the main part', - 'a.' => 'height of the main part', - 'b' => 'height of the secondary part', - 'b.' => 'height of the secondary part', - 'čas' => 'time', - 'd' => 'length', - 'd.' => 'length', - 'h' => 'depth/thickness', - 'h.' => 'depth/thickness', - 'hmot' => 'mass', - 'hmot.' => 'mass', - 'hr' => 'depth with frame', - 'jiný' => 'other, unspecified', - 'p' => 'diameter, calibre/gauge', - 'p.' => 'diameter, calibre/gauge', - 'r.' => 'calibre/gauge', - 'ryz' => 'purity', - 's' => 'width', - 's.' => 'width', - 'sd.' => 'width of the printing plate', - 'sp' => 'width with mount', - 'sp.' => 'width with mount', - 'sr' => 'width with frame', - 'v' => 'overall height/length', - 'v.' => 'overall height/length', - 'vd.' => 'height of the printing plate', - 'vp' => 'height with mount', - 'vp.' => 'height with mount', - 'vr' => 'height with frame', - '=' => ' ', + 'a=' => 'height of the main part ', + 'a.=' => 'height of the main part ', + 'b=' => 'height of the secondary part ', + 'b.=' => 'height of the secondary part ', + 'čas=' => 'time ', + 'd=' => 'length ', + 'd.=' => 'length ', + 'h=' => 'depth/thickness ', + 'h.=' => 'depth/thickness ', + 'hmot=' => 'mass ', + 'hmot.=' => 'mass ', + 'hr=' => 'depth with frame ', + 'jiný=' => 'other, unspecified ', + 'p=' => 'diameter, calibre/gauge ', + 'p.=' => 'diameter, calibre/gauge ', + 'r.=' => 'calibre/gauge ', + 'ryz=' => 'purity ', + 's=' => 'width ', + 's.=' => 'width ', + 'sd.=' => 'width of the printing plate ', + 'sp=' => 'width with mount ', + 'sp.=' => 'width with mount ', + 'sr=' => 'width with frame ', + 'v=' => 'overall height/length ', + 'v.=' => 'overall height/length ', + 'vd.=' => 'height of the printing plate ', + 'vp=' => 'height with mount ', + 'vp.=' => 'height with mount ', + 'vr=' => 'height with frame ', ], 'untitled' => 'untitled', 'authority_roles' => [ diff --git a/lang/sk/item.php b/lang/sk/item.php index f15b18ba6..ae0634767 100644 --- a/lang/sk/item.php +++ b/lang/sk/item.php @@ -105,36 +105,35 @@ ], ], 'measurement_replacements' => [ - 'a' => 'výška hlavnej časti', - 'a.' => 'výška hlavnej časti', - 'b' => 'výška vedľajšej časti', - 'b.' => 'výška vedľajšej časti', - 'čas' => 'čas', - 'd' => 'dĺžka', - 'd.' => 'dĺžka', - 'h' => 'hĺbka/hrúbka', - 'h.' => 'hĺbka/hrúbka', - 'hmot' => 'hmotnosť', - 'hmot.' => 'hmotnosť', - 'hr' => 'hĺbka s rámom', - 'jiný' => 'nešpecifikované', - 'p' => 'priemer', - 'p.' => 'priemer', - 'r.' => 'ráž', - 'ryz' => 'rýdzosť', - 's' => 'šírka', - 's.' => 'šírka', - 'sd.' => 'šírka grafickej plochy', - 'sp' => 'šírka s paspartou', - 'sp.' => 'šírka s paspartou', - 'sr' => 'šírka s rámom', - 'v' => 'celková výška/dĺžka', - 'v.' => 'celková výška/dĺžka', - 'vd.' => 'výška grafickej dosky', - 'vp' => 'výška s paspartou', - 'vp.' => 'výška s paspartou', - 'vr' => 'výška s rámom', - '=' => ' ', + 'a=' => 'výška hlavnej časti ', + 'a.=' => 'výška hlavnej časti ', + 'b=' => 'výška vedľajšej časti ', + 'b.=' => 'výška vedľajšej časti ', + 'čas=' => 'čas ', + 'd=' => 'dĺžka ', + 'd.=' => 'dĺžka ', + 'h=' => 'hĺbka/hrúbka ', + 'h.=' => 'hĺbka/hrúbka ', + 'hmot=' => 'hmotnosť ', + 'hmot.=' => 'hmotnosť ', + 'hr=' => 'hĺbka s rámom' , + 'jiný=' => 'nešpecifikované ', + 'p=' => 'priemer ', + 'p.=' => 'priemer ', + 'r.=' => 'ráž ', + 'ryz=' => 'rýdzosť ', + 's=' => 'šírka ', + 's.=' => 'šírka ', + 'sd.=' => 'šírka grafickej plochy ', + 'sp=' => 'šírka s paspartou ', + 'sp.=' => 'šírka s paspartou ', + 'sr=' => 'šírka s rámom ', + 'v=' => 'celková výška/dĺžka ', + 'v.=' => 'celková výška/dĺžka ', + 'vd.=' => 'výška grafickej dosky ', + 'vp=' => 'výška s paspartou ', + 'vp.=' => 'výška s paspartou ', + 'vr=' => 'výška s rámom ', ], 'untitled' => 'bez názvu', 'authority_roles' => [ diff --git a/tests/Importers/UpmImporterTest.php b/tests/Importers/UpmImporterTest.php new file mode 100644 index 000000000..86a54b2d0 --- /dev/null +++ b/tests/Importers/UpmImporterTest.php @@ -0,0 +1,113 @@ +repositoryMock = $this->createMock(CsvRepository::class); + $this->importer = new UpmImporter( + app(AuthorityMatcher::class), + $this->repositoryMock, + app(Translator::class) + ); + } + + public function testImport() + { + $this->importData(); + + $item = Item::find('CZE:UPM.GK_11090'); + + $this->assertEquals('GK 11090/E', $item->identifier); + $this->assertEquals('Luboš Kopáč (návrh vazby)', $item->author); + $this->assertEquals(1928, $item->date_earliest); + $this->assertEquals(1928, $item->date_latest); + $this->assertEquals('1986', $item->acquisition_date); + $this->assertEquals('Vazba knihy', $item->translate('sk')->title); + $this->assertEquals('Vazba knihy', $item->translate('cs')->title); + $this->assertEquals('Binding design', $item->translate('en')->title); + $this->assertEquals('celková výška/dĺžka 19,2cm; šírka 12cm', $item->translate('sk')->measurement); + $this->assertEquals('celková výška/délka 19,2cm; šířka 12cm', $item->translate('cs')->measurement); + $this->assertEquals('overall height/length 19,2cm; width 12cm', $item->translate('en')->measurement); + $this->assertEquals('zo súboru', $item->translate('sk')->relationship_type); + $this->assertEquals('ze souboru', $item->translate('cs')->relationship_type); + $this->assertEquals('collection', $item->translate('en')->relationship_type); + $this->assertEquals('Sbírka užité grafiky', $item->translate('cs')->related_work); + $this->assertEquals('užité umění;grafický design', $item->translate('cs')->work_type); // todo translate + $this->assertEquals('celokožená vazba, zlacení', $item->translate('cs')->technique); // todo translate + $this->assertEquals('kniha', $item->translate('cs')->object_type); // todo translate + $this->assertEquals('kůže;papír', $item->translate('cs')->medium); // todo translate + $this->assertEquals('ornament', $item->translate('cs')->topic); // todo translate + $this->assertEquals('1928', $item->translate('cs')->dating); + $this->assertEquals('Praha', $item->translate('cs')->place); + $this->assertEquals('Rösller', $item->translate('cs')->inscription); + $this->assertEquals('VŠUP atelier V.H.Brunnera (vazba)', $item->translate('cs')->additionals['producer']); + $this->assertEquals('převod', $item->translate('cs')->additionals['acquisition']); + $this->assertEquals('Japonsko design, 2019-2020', $item->translate('cs')->additionals['exhibition']); + } + + private function importData(array $data = []): ImportRecord + { + $data = $this->fakeData($data); + + $this->repositoryMock->method('getFiltered')->willReturn(new \ArrayIterator([$data])); + + $importRecord = ImportRecord::factory() + ->for(Import::factory()) + ->create(); + $this->importer->import($importRecord, stream: null); + return $importRecord; + } + + private function fakeData(array $overrides = []): array + { + return $overrides + [ + "Inventárníčíslo" => "GK 11090/E", + "ID" => "GK_11090", + "Název" => "Vazba knihy", + "Název EN" => "Binding design", + "Autor" => "Kopáč, Luboš – návrh vazby", + "Vznik" => "Praha;VŠUP atelier V.H.Brunnera (vazba)", + "Datace" => "1928", + "Od" => "1928", + "Do" => "1928", + "Výtvarný druh" => "užité umění;grafický design", + "Typ" => "kniha", + "Materiál" => "kůže;papír", + "Technika" => "celokožená vazba, zlacení", + "Rozměry" => "v=19,2cm; s=12cm", + "Námět" => "ornament", + "tagy" => "", + "Značení" => "Rösller", + "Způsob akvizice" => "převod", + "Datum akvizice" => "1986", + "Výstava" => "Japonsko design, 2019-2020", + "Publikovat" => "Y", + "Sbírka" => "Sbírka užité grafiky", + "" => "Kolbersb", + ]; + } +} \ No newline at end of file