From 655e570f0b2b4df6df82d1c87be705dd27936701 Mon Sep 17 00:00:00 2001 From: Juha Luoma Date: Mon, 8 Dec 2025 13:14:47 +0200 Subject: [PATCH 01/13] Adjusted to use only one enrichment service, map enrichment names properly to avoid multiple instances. --- .../Base/Enrichment/AuthEnrichment.php | 44 +++++- .../Base/Enrichment/Ead3SkosmosEnrichment.php | 97 -------------- .../Base/Enrichment/EadSkosmosEnrichment.php | 61 --------- .../Base/Enrichment/LidoSkosmosEnrichment.php | 92 ------------- .../Base/Enrichment/LrmiSkosmosEnrichment.php | 63 --------- .../Base/Enrichment/MarcAuthEnrichment.php | 71 ---------- .../Enrichment/MarcAuthSkosmosEnrichment.php | 71 ---------- .../Base/Enrichment/MarcSkosmosEnrichment.php | 63 --------- .../Base/Enrichment/SkosmosEnrichment.php | 125 +++++++++++++++++- src/RecordManager/Base/Solr/SolrUpdater.php | 64 +++++++-- .../Base/config/module.config.php | 22 --- .../Base/Solr/SolrUpdaterTest.php | 60 ++++++++- 12 files changed, 276 insertions(+), 557 deletions(-) delete mode 100644 src/RecordManager/Base/Enrichment/Ead3SkosmosEnrichment.php delete mode 100644 src/RecordManager/Base/Enrichment/EadSkosmosEnrichment.php delete mode 100644 src/RecordManager/Base/Enrichment/LidoSkosmosEnrichment.php delete mode 100644 src/RecordManager/Base/Enrichment/LrmiSkosmosEnrichment.php delete mode 100644 src/RecordManager/Base/Enrichment/MarcAuthEnrichment.php delete mode 100644 src/RecordManager/Base/Enrichment/MarcAuthSkosmosEnrichment.php delete mode 100644 src/RecordManager/Base/Enrichment/MarcSkosmosEnrichment.php diff --git a/src/RecordManager/Base/Enrichment/AuthEnrichment.php b/src/RecordManager/Base/Enrichment/AuthEnrichment.php index 9b8040468..7595feae5 100644 --- a/src/RecordManager/Base/Enrichment/AuthEnrichment.php +++ b/src/RecordManager/Base/Enrichment/AuthEnrichment.php @@ -52,7 +52,7 @@ * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link https://github.com/NatLibFi/RecordManager */ -abstract class AuthEnrichment extends AbstractEnrichment +class AuthEnrichment extends AbstractEnrichment { use \RecordManager\Base\Record\CreateRecordTrait; @@ -95,6 +95,48 @@ public function __construct( $this->authorityDb = $authorityDb; } + /** + * Enrich the record and return any additions in solrArray + * + * @param string $sourceId Source ID + * @param object $record Metadata Record + * @param array $solrArray Metadata to be sent to Solr + * + * @throws \Exception + * @return void + */ + public function enrich($sourceId, $record, &$solrArray) + { + if ($record instanceof \RecordManager\Base\Record\Marc) { + $this->enrichMarcRecord($sourceId, $record, $solrArray); + } + } + + /** + * Enrich the Marc record and save any additions in solrArray + * + * @param string $sourceId Source ID + * @param object $record Metadata Record + * @param array $solrArray Metadata to be sent to Solr + * + * @throws \Exception + * @return void + */ + public function enrichMarcRecord($sourceId, $record, &$solrArray): void + { + foreach ($solrArray['author2_id_str_mv'] ?? [] as $id) { + $this->enrichField( + $sourceId, + $record, + $solrArray, + $id, + 'author_variant', + 'author_variant', + true + ); + } + } + /** * Enrich the record and return any additions in solrArray * diff --git a/src/RecordManager/Base/Enrichment/Ead3SkosmosEnrichment.php b/src/RecordManager/Base/Enrichment/Ead3SkosmosEnrichment.php deleted file mode 100644 index be6492794..000000000 --- a/src/RecordManager/Base/Enrichment/Ead3SkosmosEnrichment.php +++ /dev/null @@ -1,97 +0,0 @@ - - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ - -namespace RecordManager\Base\Enrichment; - -/** - * Ead3SkosmosEnrichment Class - * - * This is a class for enrichment of EAD3 records from a Skosmos instance. - * - * @category DataManagement - * @package RecordManager - * @author Ere Maijala - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ -class Ead3SkosmosEnrichment extends SkosmosEnrichment -{ - /** - * Default fields to enrich. Key is the method in driver and value is array - * - pref, preferred field in solr - * - alt, alternative field in solr - * - check, check field for existing values - * - * @var array - */ - protected $defaultFields = [ - 'getRawTopicIds' => [ - 'pref' => 'topic_add_txt_mv', - 'alt' => 'topic_alt_txt_mv', - 'check' => 'topic', - ], - 'getRawGeographicTopicIds' => [ - 'pref' => 'geographic_add_txt_mv', - 'alt' => 'geographic_alt_txt_mv', - 'check' => 'geographic', - ], - 'getCorporateAuthorIds' => [ - 'pref' => 'author_corporate', - 'alt' => 'author_variant', - 'check' => 'author_corporate', - ], - 'getAuthorIds' => [ - 'pref' => 'author', - 'alt' => 'author_variant', - 'check' => 'author', - ], - 'getSecondaryAuthorIds' => [ - 'pref' => 'author2', - 'alt' => 'author2_variant', - 'check' => 'author2', - ], - ]; - - /** - * Enrich the record and return any additions in solrArray - * - * @param string $sourceId Source ID - * @param object $record Metadata Record - * @param array $solrArray Metadata to be sent to Solr - * - * @return void - */ - public function enrich($sourceId, $record, &$solrArray) - { - if (!($record instanceof \RecordManager\Base\Record\Ead3)) { - return; - } - parent::enrich($sourceId, $record, $solrArray); - } -} diff --git a/src/RecordManager/Base/Enrichment/EadSkosmosEnrichment.php b/src/RecordManager/Base/Enrichment/EadSkosmosEnrichment.php deleted file mode 100644 index 1bf12b180..000000000 --- a/src/RecordManager/Base/Enrichment/EadSkosmosEnrichment.php +++ /dev/null @@ -1,61 +0,0 @@ - - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ - -namespace RecordManager\Base\Enrichment; - -/** - * EadSkosmosEnrichment Class - * - * This is a class for enrichment of EAD records from a Skosmos instance. - * - * @category DataManagement - * @package RecordManager - * @author Samuli Sillanpää - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ -class EadSkosmosEnrichment extends SkosmosEnrichment -{ - /** - * Enrich the record and return any additions in solrArray - * - * @param string $sourceId Source ID - * @param object $record Metadata Record - * @param array $solrArray Metadata to be sent to Solr - * - * @return void - */ - public function enrich($sourceId, $record, &$solrArray) - { - if (!($record instanceof \RecordManager\Base\Record\Ead)) { - return; - } - parent::enrich($sourceId, $record, $solrArray); - } -} diff --git a/src/RecordManager/Base/Enrichment/LidoSkosmosEnrichment.php b/src/RecordManager/Base/Enrichment/LidoSkosmosEnrichment.php deleted file mode 100644 index cfb1183ce..000000000 --- a/src/RecordManager/Base/Enrichment/LidoSkosmosEnrichment.php +++ /dev/null @@ -1,92 +0,0 @@ - - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ - -namespace RecordManager\Base\Enrichment; - -/** - * LidoSkosmosEnrichment Class - * - * This is a class for enrichment of LIDO records from a Skosmos instance. - * - * @category DataManagement - * @package RecordManager - * @author Ere Maijala - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ -class LidoSkosmosEnrichment extends SkosmosEnrichment -{ - /** - * Default fields to enrich. Key is the method in driver and value is array - * - pref, preferred field in solr - * - alt, alternative field in solr - * - check, check field for existing values - * - * @var array - */ - protected $defaultFields = [ - 'getRawTopicIds' => [ - 'pref' => 'topic_add_txt_mv', - 'alt' => 'topic_alt_txt_mv', - 'check' => 'topic', - ], - 'getRawGeographicTopicIds' => [ - 'pref' => 'geographic_add_txt_mv', - 'alt' => 'geographic_alt_txt_mv', - 'check' => 'geographic', - ], - 'getAuthorIds' => [ - 'pref' => 'author', - 'alt' => 'author_variant', - 'check' => 'author', - ], - 'getSecondaryAuthorIds' => [ - 'pref' => 'author2', - 'alt' => 'author2_variant', - 'check' => 'author2', - ], - ]; - - /** - * Enrich the record and return any additions in solrArray - * - * @param string $sourceId Source ID - * @param object $record Metadata Record - * @param array $solrArray Metadata to be sent to Solr - * - * @return void - */ - public function enrich($sourceId, $record, &$solrArray) - { - if (!($record instanceof \RecordManager\Base\Record\Lido)) { - return; - } - parent::enrich($sourceId, $record, $solrArray); - } -} diff --git a/src/RecordManager/Base/Enrichment/LrmiSkosmosEnrichment.php b/src/RecordManager/Base/Enrichment/LrmiSkosmosEnrichment.php deleted file mode 100644 index 2787f7a84..000000000 --- a/src/RecordManager/Base/Enrichment/LrmiSkosmosEnrichment.php +++ /dev/null @@ -1,63 +0,0 @@ - - * @author Samuli Sillanpää - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ - -namespace RecordManager\Base\Enrichment; - -/** - * LrmiSkosmosEnrichment Class - * - * This is a class for enrichment of MARC records from a Skosmos instance. - * - * @category DataManagement - * @package RecordManager - * @author Ere Maijala - * @author Samuli Sillanpää - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ -class LrmiSkosmosEnrichment extends SkosmosEnrichment -{ - /** - * Enrich the record and return any additions in solrArray - * - * @param string $sourceId Source ID - * @param object $record Metadata Record - * @param array $solrArray Metadata to be sent to Solr - * - * @return void - */ - public function enrich($sourceId, $record, &$solrArray) - { - if (!($record instanceof \RecordManager\Base\Record\Lrmi)) { - return; - } - parent::enrich($sourceId, $record, $solrArray); - } -} diff --git a/src/RecordManager/Base/Enrichment/MarcAuthEnrichment.php b/src/RecordManager/Base/Enrichment/MarcAuthEnrichment.php deleted file mode 100644 index e32c79caa..000000000 --- a/src/RecordManager/Base/Enrichment/MarcAuthEnrichment.php +++ /dev/null @@ -1,71 +0,0 @@ - - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ - -namespace RecordManager\Base\Enrichment; - -/** - * Enrich Marc biblio records with authority record data. - * - * @category DataManagement - * @package RecordManager - * @author Samuli Sillanpää - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ -class MarcAuthEnrichment extends AuthEnrichment -{ - /** - * Enrich the record and return any additions in solrArray - * - * @param string $sourceId Source ID - * @param object $record Metadata Record - * @param array $solrArray Metadata to be sent to Solr - * - * @throws \Exception - * @return void - */ - public function enrich($sourceId, $record, &$solrArray) - { - if (!($record instanceof \RecordManager\Base\Record\Marc)) { - return; - } - - foreach ($solrArray['author2_id_str_mv'] ?? [] as $id) { - $this->enrichField( - $sourceId, - $record, - $solrArray, - $id, - 'author_variant', - 'author_variant', - true - ); - } - } -} diff --git a/src/RecordManager/Base/Enrichment/MarcAuthSkosmosEnrichment.php b/src/RecordManager/Base/Enrichment/MarcAuthSkosmosEnrichment.php deleted file mode 100644 index 09fd512cc..000000000 --- a/src/RecordManager/Base/Enrichment/MarcAuthSkosmosEnrichment.php +++ /dev/null @@ -1,71 +0,0 @@ - - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ - -namespace RecordManager\Base\Enrichment; - -/** - * Enrich Marc authority records with data from a Skosmos instance. - * - * @category DataManagement - * @package RecordManager - * @author Samuli Sillanpää - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ -class MarcAuthSkosmosEnrichment extends SkosmosEnrichment -{ - /** - * Enrich the record and return any additions in solrArray - * - * @param string $sourceId Source ID - * @param object $record Metadata Record - * @param array $solrArray Metadata to be sent to Solr - * - * @throws \Exception - * @return void - */ - public function enrich($sourceId, $record, &$solrArray) - { - if (!($record instanceof \RecordManager\Base\Record\MarcAuthority)) { - return; - } - foreach ($record->getOccupationIds() as $id) { - $this->enrichField( - $sourceId, - $record, - $solrArray, - $id, - 'occupation_str_mv', - '', - '', - true - ); - } - } -} diff --git a/src/RecordManager/Base/Enrichment/MarcSkosmosEnrichment.php b/src/RecordManager/Base/Enrichment/MarcSkosmosEnrichment.php deleted file mode 100644 index 4f7d8357d..000000000 --- a/src/RecordManager/Base/Enrichment/MarcSkosmosEnrichment.php +++ /dev/null @@ -1,63 +0,0 @@ - - * @author Samuli Sillanpää - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ - -namespace RecordManager\Base\Enrichment; - -/** - * MarcSkosmosEnrichment Class - * - * This is a class for enrichment of MARC records from a Skosmos instance. - * - * @category DataManagement - * @package RecordManager - * @author Ere Maijala - * @author Samuli Sillanpää - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ -class MarcSkosmosEnrichment extends SkosmosEnrichment -{ - /** - * Enrich the record and return any additions in solrArray - * - * @param string $sourceId Source ID - * @param object $record Metadata Record - * @param array $solrArray Metadata to be sent to Solr - * - * @return void - */ - public function enrich($sourceId, $record, &$solrArray) - { - if (!($record instanceof \RecordManager\Base\Record\Marc)) { - return; - } - parent::enrich($sourceId, $record, $solrArray); - } -} diff --git a/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php b/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php index a61c60a64..625d3d5c3 100644 --- a/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php +++ b/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php @@ -5,7 +5,7 @@ * * PHP version 8 * - * Copyright (C) The National Library of Finland 2014-2023. + * Copyright (C) The National Library of Finland 2014-2025. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -24,6 +24,7 @@ * @package RecordManager * @author Ere Maijala * @author Samuli Sillanpää + * @author Juha Luoma * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link https://github.com/NatLibFi/RecordManager */ @@ -48,6 +49,7 @@ * @package RecordManager * @author Ere Maijala * @author Samuli Sillanpää + * @author Juha Luoma * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link https://github.com/NatLibFi/RecordManager */ @@ -155,6 +157,73 @@ class SkosmosEnrichment extends AbstractEnrichment */ protected $excludedLocationMatches = []; + /** + * Default fields to enrich. Key is the method in driver and value is array + * - pref, preferred field in solr + * - alt, alternative field in solr + * - check, check field for existing values + * + * @var array + */ + protected $ead3Fields = [ + 'getRawTopicIds' => [ + 'pref' => 'topic_add_txt_mv', + 'alt' => 'topic_alt_txt_mv', + 'check' => 'topic', + ], + 'getRawGeographicTopicIds' => [ + 'pref' => 'geographic_add_txt_mv', + 'alt' => 'geographic_alt_txt_mv', + 'check' => 'geographic', + ], + 'getCorporateAuthorIds' => [ + 'pref' => 'author_corporate', + 'alt' => 'author_variant', + 'check' => 'author_corporate', + ], + 'getAuthorIds' => [ + 'pref' => 'author', + 'alt' => 'author_variant', + 'check' => 'author', + ], + 'getSecondaryAuthorIds' => [ + 'pref' => 'author2', + 'alt' => 'author2_variant', + 'check' => 'author2', + ], + ]; + + /** + * Default fields to enrich. Key is the method in driver and value is array + * - pref, preferred field in solr + * - alt, alternative field in solr + * - check, check field for existing values + * + * @var array + */ + protected $lidoFields = [ + 'getRawTopicIds' => [ + 'pref' => 'topic_add_txt_mv', + 'alt' => 'topic_alt_txt_mv', + 'check' => 'topic', + ], + 'getRawGeographicTopicIds' => [ + 'pref' => 'geographic_add_txt_mv', + 'alt' => 'geographic_alt_txt_mv', + 'check' => 'geographic', + ], + 'getAuthorIds' => [ + 'pref' => 'author', + 'alt' => 'author_variant', + 'check' => 'author', + ], + 'getSecondaryAuthorIds' => [ + 'pref' => 'author2', + 'alt' => 'author2_variant', + 'check' => 'author2', + ], + ]; + /** * Initialize settings * @@ -221,7 +290,59 @@ public function init() */ public function enrich($sourceId, $record, &$solrArray) { - foreach ($this->defaultFields as $method => $spec) { + // Detect if record is an authority record or not as they have different enrichments. + if (str_ends_with($record::class, 'Authority')) { + $this->enrichAuthorityRecord($sourceId, $record, $solrArray); + } else { + $this->enrichRecord($sourceId, $record, $solrArray); + } + } + + /** + * Enrich the authority record and save any additions in solrArray + * + * @param string $sourceId Source ID + * @param object $record Metadata Record + * @param array $solrArray Metadata to be sent to Solr + * + * @throws \Exception + * @return void + */ + protected function enrichAuthorityRecord($sourceId, $record, &$solrArray): void + { + foreach ($record->getOccupationIds() as $id) { + $this->enrichField( + $sourceId, + $record, + $solrArray, + $id, + 'occupation_str_mv', + '', + '', + true + ); + } + } + + /** + * Enrich the record and save any additions in solrArray + * + * @param string $sourceId Source ID + * @param object $record Metadata Record + * @param array $solrArray Metadata to be sent to Solr + * + * @throws \Exception + * @return void + */ + protected function enrichRecord($sourceId, $record, &$solrArray): void + { + $enrichFieldSpecs = $this->defaultFields; + if ($record instanceof \RecordManager\Base\Record\Lido) { + $enrichFieldSpecs = $this->lidoFields; + } elseif ($record instanceof \RecordManager\Base\Record\Ead3) { + $enrichFieldSpecs = $this->ead3Fields; + } + foreach ($enrichFieldSpecs as $method => $spec) { if (!is_callable([$record, $method])) { continue; } diff --git a/src/RecordManager/Base/Solr/SolrUpdater.php b/src/RecordManager/Base/Solr/SolrUpdater.php index 17cb8355f..e310b7612 100644 --- a/src/RecordManager/Base/Solr/SolrUpdater.php +++ b/src/RecordManager/Base/Solr/SolrUpdater.php @@ -3106,23 +3106,61 @@ protected function enrich($source, $settings, $record, &$data, $stage = '') /** @psalm-var list $dsEnrichments */ $dsEnrichments = (array)($settings['enrichments'] ?? []); $enrichments = array_unique( - [ - ...$globalEnrichments, - ...$dsEnrichments, - ] + array_map( + /** + * Bc support: map all instances of recordOnkiLightEnrichment and recordSkosmosEnrichment to + * use SkosmosEnrichment instead and recordAuthEnrichment instances + * to use AuthEnrichment instead. + * + * This will help to map all instances under the same key. + */ + function ($enrichment) { + $exploded = explode(',', $enrichment, 2); + $enrichmentName = $exploded[0]; + $enrichmentStage = $exploded[1] ?? ''; + if (!$enrichment[0]) { + return []; + } + if ( + str_ends_with($enrichmentName, 'OnkiLightEnrichment') + || str_ends_with($enrichmentName, 'SkosmosEnrichment') + ) { + return [ + 'name' => 'SkosmosEnrichment', + 'stage' => $enrichmentStage, + ]; + } + if (str_ends_with($enrichmentName, 'AuthEnrichment')) { + return [ + 'name' => 'AuthEnrichment', + 'stage' => $enrichmentStage, + ]; + } + return [ + 'name' => $enrichmentName, + 'stage' => $enrichmentStage, + ]; + }, + [ + ...$globalEnrichments, + ...$dsEnrichments, + ] + ), + SORT_REGULAR ); - foreach ($enrichments as $enrichmentSettings) { - $parts = explode(',', $enrichmentSettings); - $enrichment = $parts[0]; - $enrichmentStage = $parts[1] ?? ''; - if ($stage !== $enrichmentStage) { + foreach ($enrichments as $enrichment) { + if (!$enrichment || $stage !== $enrichment['stage']) { continue; } - if (!isset($this->enrichments[$enrichment])) { - $this->enrichments[$enrichment] - = $this->enrichmentPluginManager->get($enrichment); + $enrichmentName = $enrichment['name']; + if (!isset($this->enrichments[$enrichmentName])) { + if ($enrichmentService = $this->enrichmentPluginManager->get($enrichmentName)) { + $this->enrichments[$enrichmentName] = $enrichmentService; + } else { + continue; + } } - $this->enrichments[$enrichment]->enrich($source, $record, $data); + $this->enrichments[$enrichmentName]->enrich($source, $record, $data); } } diff --git a/src/RecordManager/Base/config/module.config.php b/src/RecordManager/Base/config/module.config.php index 1cc04b092..693fb93b1 100644 --- a/src/RecordManager/Base/config/module.config.php +++ b/src/RecordManager/Base/config/module.config.php @@ -70,37 +70,15 @@ 'enrichment' => [ 'factories' => [ \RecordManager\Base\Enrichment\AuthEnrichment::class => \RecordManager\Base\Enrichment\AuthEnrichmentFactory::class, - \RecordManager\Base\Enrichment\EadSkosmosEnrichment::class => \RecordManager\Base\Enrichment\AbstractEnrichmentFactory::class, - \RecordManager\Base\Enrichment\Ead3SkosmosEnrichment::class => \RecordManager\Base\Enrichment\AbstractEnrichmentFactory::class, - \RecordManager\Base\Enrichment\LidoSkosmosEnrichment::class => \RecordManager\Base\Enrichment\AbstractEnrichmentFactory::class, - \RecordManager\Base\Enrichment\LrmiSkosmosEnrichment::class => \RecordManager\Base\Enrichment\AbstractEnrichmentFactory::class, - \RecordManager\Base\Enrichment\MarcAuthEnrichment::class => \RecordManager\Base\Enrichment\AuthEnrichmentFactory::class, - \RecordManager\Base\Enrichment\MarcAuthSkosmosEnrichment::class => \RecordManager\Base\Enrichment\AbstractEnrichmentFactory::class, - \RecordManager\Base\Enrichment\MarcSkosmosEnrichment::class => \RecordManager\Base\Enrichment\AbstractEnrichmentFactory::class, \RecordManager\Base\Enrichment\MusicBrainzEnrichment::class => \RecordManager\Base\Enrichment\AbstractEnrichmentFactory::class, \RecordManager\Base\Enrichment\NominatimGeocoder::class => \RecordManager\Base\Enrichment\AbstractEnrichmentFactory::class, \RecordManager\Base\Enrichment\SkosmosEnrichment::class => \RecordManager\Base\Enrichment\AbstractEnrichmentFactory::class, ], 'aliases' => [ 'AuthEnrichment' => \RecordManager\Base\Enrichment\AuthEnrichment::class, - 'EadSkosmosEnrichment' => \RecordManager\Base\Enrichment\EadSkosmosEnrichment::class, - 'Ead3SkosmosEnrichment' => \RecordManager\Base\Enrichment\Ead3SkosmosEnrichment::class, - 'LidoSkosmosEnrichment' => \RecordManager\Base\Enrichment\LidoSkosmosEnrichment::class, - 'LrmiSkosmosEnrichment' => \RecordManager\Base\Enrichment\LrmiSkosmosEnrichment::class, - 'MarcAuthEnrichment' => \RecordManager\Base\Enrichment\MarcAuthEnrichment::class, - 'MarcAuthSkosmosEnrichment' => \RecordManager\Base\Enrichment\MarcAuthSkosmosEnrichment::class, - 'MarcSkosmosEnrichment' => \RecordManager\Base\Enrichment\MarcSkosmosEnrichment::class, 'MusicBrainzEnrichment' => \RecordManager\Base\Enrichment\MusicBrainzEnrichment::class, 'NominatimGeocoder' => \RecordManager\Base\Enrichment\NominatimGeocoder::class, 'SkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, - - 'EadOnkiLightEnrichment' => 'EadSkosmosEnrichment', - 'Ead3OnkiLightEnrichment' => 'Ead3SkosmosEnrichment', - 'LidoOnkiLightEnrichment' => 'LidoSkosmosEnrichment', - 'LrmiOnkiLightEnrichment' => 'LrmiSkosmosEnrichment', - 'MarcAuthOnkiLightEnrichment' => 'MarcAuthSkosmosEnrichment', - 'MarcOnkiLightEnrichment' => 'MarcSkosmosEnrichment', - 'OnkiLightEnrichment' => 'SkosmosEnrichment', ], ], 'harvest' => [ diff --git a/tests/RecordManagerTest/Base/Solr/SolrUpdaterTest.php b/tests/RecordManagerTest/Base/Solr/SolrUpdaterTest.php index ea3ee0ba9..e06304566 100644 --- a/tests/RecordManagerTest/Base/Solr/SolrUpdaterTest.php +++ b/tests/RecordManagerTest/Base/Solr/SolrUpdaterTest.php @@ -32,7 +32,9 @@ use ArrayIterator; use RecordManager\Base\Database\DatabaseInterface; use RecordManager\Base\Database\MongoDatabase; +use RecordManager\Base\Enrichment\AuthEnrichment; use RecordManager\Base\Enrichment\PluginManager as EnrichmentPluginManager; +use RecordManager\Base\Enrichment\SkosmosEnrichment; use RecordManager\Base\Http\HttpService as HttpService; use RecordManager\Base\Record\Marc\FormatCalculator; use RecordManager\Base\Record\PluginManager as RecordPluginManager; @@ -43,6 +45,7 @@ use RecordManager\Base\Utils\WorkerPoolManager; use RecordManagerTest\Base\Feature\FixtureTrait; use RecordManagerTest\Base\Record\CreateSampleRecordTrait; +use ReflectionClass; /** * Tests for SolrUpdater @@ -450,6 +453,55 @@ public function testFieldProcessingRules(array $rules, array $expected): void } } + /** + * Test enrichments using legacy names and new names. + * + * @return void + */ + public function testLegacyEnrichments(): void + { + $dsOverride = [ + 'test' => [ + 'enrichments' => [ + 'MarcOnkiLightEnrichment', + 'LidoOnkiLightEnrichment', + 'Ead3SkosmosEnrichment', + 'EadSkosmosEnrichment', + 'OnkiLightEnrichment', + 'MarcAuthEnrichment', + 'SomeAuthEnrichment,final', + 'BrokenEnrichment', + ], + ], + ]; + $solrUpdater = $this->getSolrUpdater( + $dsOverride, + ); + $record = $this->createMarcRecord( + \RecordManager\Base\Record\Marc::class, + 'marc-broken.xml' + ); + + $date = strtotime('2020-10-20 13:01:00'); + $dbRecord = [ + '_id' => $record->getID(), + 'oai_id' => '', + 'linking_id' => $record->getLinkingIDs(), + 'source_id' => 'test', + 'deleted' => false, + 'created' => $date, + 'updated' => $date, + 'date' => $date, + 'format' => 'marc', + 'original_data' => $record->serialize(), + 'normalized_data' => null, + ]; + $solrUpdater->processSingleRecord($dbRecord); + $reflectionClass = new ReflectionClass($solrUpdater); + $enrichments = array_keys($reflectionClass->getProperty('enrichments')->getValue($solrUpdater)); + $this->assertEquals(['SkosmosEnrichment', 'AuthEnrichment'], $enrichments); + } + /** * Create SolrUpdater * @@ -491,13 +543,19 @@ function ($data) { [], $this->dataSourceConfig ); + $enrichmentMap = [ + ['SkosmosEnrichment', $this->createMock(SkosmosEnrichment::class)], + ['AuthEnrichment', $this->createMock(AuthEnrichment::class)], + ]; + $enrichmentPluginManager = $this->createMock(EnrichmentPluginManager::class); + $enrichmentPluginManager->expects($this->any())->method('get')->willReturnMap($enrichmentMap); $solrUpdater = new SolrUpdater( $this->config, $dsConfig, $database, $logger, $recordPM, - $this->createMock(EnrichmentPluginManager::class), + $enrichmentPluginManager, $this->createMock(HttpService::class), $this->createMock(Ini::class), $fieldMapper, From 4a4bbf042bf23a651a2d12d9dc0fd08628a575e0 Mon Sep 17 00:00:00 2001 From: Juha Luoma Date: Mon, 8 Dec 2025 13:34:28 +0200 Subject: [PATCH 02/13] Adjust comments --- src/RecordManager/Base/Enrichment/SkosmosEnrichment.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php b/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php index 625d3d5c3..6509db932 100644 --- a/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php +++ b/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php @@ -158,7 +158,7 @@ class SkosmosEnrichment extends AbstractEnrichment protected $excludedLocationMatches = []; /** - * Default fields to enrich. Key is the method in driver and value is array + * Default fields for ead3 to enrich. Key is the method in driver and value is array * - pref, preferred field in solr * - alt, alternative field in solr * - check, check field for existing values @@ -194,7 +194,7 @@ class SkosmosEnrichment extends AbstractEnrichment ]; /** - * Default fields to enrich. Key is the method in driver and value is array + * Default fields for lido to enrich. Key is the method in driver and value is array * - pref, preferred field in solr * - alt, alternative field in solr * - check, check field for existing values From 68dfed46eb66fb5eb9e6d731f294b58d3aff491d Mon Sep 17 00:00:00 2001 From: Juha Luoma Date: Mon, 8 Dec 2025 13:49:55 +0200 Subject: [PATCH 03/13] Adjusted test to test config settings also, adjusted sample comments --- conf/datasources.ini.sample | 4 ++-- tests/RecordManagerTest/Base/Solr/SolrUpdaterTest.php | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/conf/datasources.ini.sample b/conf/datasources.ini.sample index 60359da9d..86c4644ba 100644 --- a/conf/datasources.ini.sample +++ b/conf/datasources.ini.sample @@ -112,7 +112,7 @@ ; authority[] Map to authority index sources where is authority record type ; (corporateBody, person) or * for any; ; authority_id_regex[] Regex for filtering allowed authority ids -; (used when indexing authority ids and when enriching biblio records with MarcAuthEnrichment) +; (used when indexing authority ids and when enriching biblio records with AuthEnrichment) ; fullTextXPaths XPath expression denoting full text fields ; fullTextUrlXPaths XPath expression denoting fields that contain URLs to full text content (plain text only at the moment) @@ -162,7 +162,7 @@ ;driverParams[] = "idIn999=true" ;driverParams[] = "003InLinkingID=true" ;driverParams[] = "kohaNormalization=true" -;enrichments[] = MarcAuthEnrichment,final +;enrichments[] = AuthEnrichment,final ; Sample DSpace configuration ;[dspace] diff --git a/tests/RecordManagerTest/Base/Solr/SolrUpdaterTest.php b/tests/RecordManagerTest/Base/Solr/SolrUpdaterTest.php index e06304566..d7fb477b7 100644 --- a/tests/RecordManagerTest/Base/Solr/SolrUpdaterTest.php +++ b/tests/RecordManagerTest/Base/Solr/SolrUpdaterTest.php @@ -474,6 +474,11 @@ public function testLegacyEnrichments(): void ], ], ]; + $this->config['Solr']['enrichment'] = [ + 'LidoSkosmosEnrichment', + 'LidoAuthEnrichment', + 'EadOnkiLightEnrichment,start', + ]; $solrUpdater = $this->getSolrUpdater( $dsOverride, ); From 38dc02ccbfa0b75b9d46aa5d1db1d49cd0e57ece Mon Sep 17 00:00:00 2001 From: Juha Luoma Date: Mon, 15 Dec 2025 13:58:17 +0200 Subject: [PATCH 04/13] Added SkosmosEnrichmentTest, removed lidofields and ead3fields --- .../Base/Enrichment/SkosmosEnrichment.php | 73 +--- .../Base/Enrichment/SkosmosEnrichmentTest.php | 313 ++++++++++++++++++ .../Enrichment/skosmos_author_results.json | 14 + .../Enrichment/skosmos_authority_results.json | 25 ++ .../skosmos_exactmatch_results.json | 25 ++ .../skosmos_excluded_location_results.json | 28 ++ .../skosmos_geographic_results.json | 14 + .../Enrichment/skosmos_multilang_results.json | 28 ++ .../Base/Enrichment/skosmos_results.json | 84 +++++ tests/fixtures/Base/record/ead3_skosmos.xml | 23 ++ .../fixtures/Base/record/forward_skosmos.xml | 17 + tests/fixtures/Base/record/lido_skosmos.xml | 44 +++ .../Base/record/marc_authority_skosmos.xml | 16 + tests/fixtures/Base/record/marc_skosmos_1.xml | 19 ++ tests/fixtures/Base/record/marc_skosmos_2.xml | 19 ++ tests/fixtures/Base/record/marc_skosmos_3.xml | 15 + .../Base/record/marc_skosmos_exactmatch.xml | 19 ++ .../record/marc_skosmos_excluded_location.xml | 19 ++ .../Base/record/marc_skosmos_invalid_uri.xml | 19 ++ .../Base/record/marc_skosmos_multilang.xml | 19 ++ tests/fixtures/Base/record/qdc_skosmos.xml | 9 + 21 files changed, 776 insertions(+), 66 deletions(-) create mode 100644 tests/RecordManagerTest/Base/Enrichment/SkosmosEnrichmentTest.php create mode 100644 tests/fixtures/Base/Enrichment/skosmos_author_results.json create mode 100644 tests/fixtures/Base/Enrichment/skosmos_authority_results.json create mode 100644 tests/fixtures/Base/Enrichment/skosmos_exactmatch_results.json create mode 100644 tests/fixtures/Base/Enrichment/skosmos_excluded_location_results.json create mode 100644 tests/fixtures/Base/Enrichment/skosmos_geographic_results.json create mode 100644 tests/fixtures/Base/Enrichment/skosmos_multilang_results.json create mode 100644 tests/fixtures/Base/Enrichment/skosmos_results.json create mode 100644 tests/fixtures/Base/record/ead3_skosmos.xml create mode 100644 tests/fixtures/Base/record/forward_skosmos.xml create mode 100644 tests/fixtures/Base/record/lido_skosmos.xml create mode 100644 tests/fixtures/Base/record/marc_authority_skosmos.xml create mode 100644 tests/fixtures/Base/record/marc_skosmos_1.xml create mode 100644 tests/fixtures/Base/record/marc_skosmos_2.xml create mode 100644 tests/fixtures/Base/record/marc_skosmos_3.xml create mode 100644 tests/fixtures/Base/record/marc_skosmos_exactmatch.xml create mode 100644 tests/fixtures/Base/record/marc_skosmos_excluded_location.xml create mode 100644 tests/fixtures/Base/record/marc_skosmos_invalid_uri.xml create mode 100644 tests/fixtures/Base/record/marc_skosmos_multilang.xml create mode 100644 tests/fixtures/Base/record/qdc_skosmos.xml diff --git a/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php b/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php index 6509db932..0c95a3e2b 100644 --- a/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php +++ b/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php @@ -145,37 +145,6 @@ class SkosmosEnrichment extends AbstractEnrichment 'alt' => 'geographic_alt_txt_mv', 'check' => 'geographic', ], - ]; - - /** - * An associative array of property matches that causes the location data of a - * node to be ignored. - * - * Key is property type and value is an array of property id's. - * - * @var array - */ - protected $excludedLocationMatches = []; - - /** - * Default fields for ead3 to enrich. Key is the method in driver and value is array - * - pref, preferred field in solr - * - alt, alternative field in solr - * - check, check field for existing values - * - * @var array - */ - protected $ead3Fields = [ - 'getRawTopicIds' => [ - 'pref' => 'topic_add_txt_mv', - 'alt' => 'topic_alt_txt_mv', - 'check' => 'topic', - ], - 'getRawGeographicTopicIds' => [ - 'pref' => 'geographic_add_txt_mv', - 'alt' => 'geographic_alt_txt_mv', - 'check' => 'geographic', - ], 'getCorporateAuthorIds' => [ 'pref' => 'author_corporate', 'alt' => 'author_variant', @@ -194,35 +163,14 @@ class SkosmosEnrichment extends AbstractEnrichment ]; /** - * Default fields for lido to enrich. Key is the method in driver and value is array - * - pref, preferred field in solr - * - alt, alternative field in solr - * - check, check field for existing values + * An associative array of property matches that causes the location data of a + * node to be ignored. * - * @var array + * Key is property type and value is an array of property id's. + * + * @var array */ - protected $lidoFields = [ - 'getRawTopicIds' => [ - 'pref' => 'topic_add_txt_mv', - 'alt' => 'topic_alt_txt_mv', - 'check' => 'topic', - ], - 'getRawGeographicTopicIds' => [ - 'pref' => 'geographic_add_txt_mv', - 'alt' => 'geographic_alt_txt_mv', - 'check' => 'geographic', - ], - 'getAuthorIds' => [ - 'pref' => 'author', - 'alt' => 'author_variant', - 'check' => 'author', - ], - 'getSecondaryAuthorIds' => [ - 'pref' => 'author2', - 'alt' => 'author2_variant', - 'check' => 'author2', - ], - ]; + protected $excludedLocationMatches = []; /** * Initialize settings @@ -336,13 +284,7 @@ protected function enrichAuthorityRecord($sourceId, $record, &$solrArray): void */ protected function enrichRecord($sourceId, $record, &$solrArray): void { - $enrichFieldSpecs = $this->defaultFields; - if ($record instanceof \RecordManager\Base\Record\Lido) { - $enrichFieldSpecs = $this->lidoFields; - } elseif ($record instanceof \RecordManager\Base\Record\Ead3) { - $enrichFieldSpecs = $this->ead3Fields; - } - foreach ($enrichFieldSpecs as $method => $spec) { + foreach ($this->defaultFields as $method => $spec) { if (!is_callable([$record, $method])) { continue; } @@ -528,7 +470,6 @@ protected function getEnrichmentData(string $id, string $recordId): array if (!$this->isConceptNode($node)) { continue; } - if ($node->getId() === $id) { if ($locs = $this->processLocationWgs84($node, $recordId)) { $result['locations'] = [ diff --git a/tests/RecordManagerTest/Base/Enrichment/SkosmosEnrichmentTest.php b/tests/RecordManagerTest/Base/Enrichment/SkosmosEnrichmentTest.php new file mode 100644 index 000000000..c6e0e195d --- /dev/null +++ b/tests/RecordManagerTest/Base/Enrichment/SkosmosEnrichmentTest.php @@ -0,0 +1,313 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/NatLibFi/RecordManager + */ + +namespace RecordManagerTest\Base\Enrichment; + +use Generator; +use RecordManager\Base\Enrichment\SkosmosEnrichment; +use RecordManager\Base\Http\HttpService; +use RecordManager\Base\Record\Marc; +use RecordManager\Base\Record\MarcAuthority; +use RecordManager\Base\Record\PluginManager; +use RecordManager\Base\Utils\Logger; +use RecordManager\Base\Utils\MetadataUtils; +use RecordManagerTest\Base\Record\RecordTestBase; + +use function is_array; + +/** + * Skosmos enrichment test class + * + * @category DataManagement + * @package RecordManager + * @author Juha Luoma + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/NatLibFi/RecordManager + */ +class SkosmosEnrichmentTest extends RecordTestBase +{ + /** + * Data provider for testing Skosmos enrichment + * + * @return Generator + */ + public static function getSkosmosEnrichmentData(): Generator + { + yield 'basic topic enrichment' => [ + 'fixture' => 'marc_skosmos_1.xml', + 'enrichmentFixture' => 'Enrichment/skosmos_results.json', + 'config' => [], + 'expected' => [ + 'topic_add_txt_mv' => ['Enhanced Topic', 'Förbättrat ämne'], + 'topic_alt_txt_mv' => ['Alternative Topic'], + ], + ]; + yield 'geographic enrichment' => [ + 'fixture' => 'marc_skosmos_2.xml', + 'enrichmentFixture' => 'Enrichment/skosmos_results.json', + 'config' => [], + 'expected' => [ + 'geographic_add_txt_mv' => ['Helsinki', 'Helsingfors'], + 'location_geo' => ['POINT(24.9384 60.1699)'], + 'center_coords' => '60.1699, 24.9384', + ], + ]; + yield 'author enrichment (no method in Marc)' => [ + 'fixture' => 'marc_skosmos_3.xml', + 'enrichmentFixture' => 'Enrichment/skosmos_results.json', + 'config' => [], + 'expected' => [ + // Marc class doesn't have getAuthorIds() method, so enrichment won't occur + // Author field remains unchanged from the MARC record + 'author' => ['Test Author'], + ], + ]; + yield 'authority record enrichment' => [ + 'fixture' => 'marc_authority_skosmos.xml', + 'enrichmentFixture' => 'Enrichment/skosmos_authority_results.json', + 'config' => [], + 'expected' => [ + 'occupation_str_mv' => [ + 'Test Occupation', + ], + ], + ]; + yield 'URI prefix filtering (invalid URI)' => [ + 'fixture' => 'marc_skosmos_invalid_uri.xml', + 'enrichmentFixture' => null, + 'config' => [], + 'expected' => [ + 'topic_add_txt_mv' => [], + ], + ]; + yield 'exact match enrichment' => [ + 'fixture' => 'marc_skosmos_exactmatch.xml', + 'enrichmentFixture' => 'Enrichment/skosmos_exactmatch_results.json', + 'config' => [], + 'expected' => [ + 'topic_add_txt_mv' => [ + 'Exact Match Enhanced Topic', + ], + ], + ]; + yield 'language filtering' => [ + 'fixture' => 'marc_skosmos_multilang.xml', + 'enrichmentFixture' => 'Enrichment/skosmos_multilang_results.json', + 'config' => [ + 'SkosmosEnrichment' => [ + 'base_url' => 'http://test.skosmos.url', + 'url_prefix_allowed_list' => ['http://www.yso.fi/onto/yso/'], + 'languages' => ['en', 'fi'], + ], + ], + 'expected' => [ + 'topic_add_txt_mv' => [ + 'Multilingual Topic English', + 'Monikielinen aihe suomeksi', + ], + ], + ]; + yield 'excluded location matches' => [ + 'fixture' => 'marc_skosmos_excluded_location.xml', + 'enrichmentFixture' => 'Enrichment/skosmos_excluded_location_results.json', + 'config' => [], + 'expected' => [ + 'location_geo' => ['POINT(23.7610 61.4978)'], + ], + ]; + yield 'EAD3 with topic enrichment' => [ + 'fixture' => 'ead3_skosmos.xml', + 'enrichmentFixture' => 'Enrichment/skosmos_results.json', + 'config' => [], + 'expected' => [ + 'topic_add_txt_mv' => ['Enhanced Topic', 'Förbättrat ämne'], + ], + ]; + yield 'LIDO with topic enrichment' => [ + 'fixture' => 'lido_skosmos.xml', + 'enrichmentFixture' => 'Enrichment/skosmos_results.json', + 'config' => [], + 'expected' => [ + 'topic_add_txt_mv' => ['Enhanced Topic', 'Förbättrat ämne'], + ], + ]; + yield 'QDC without enrichment methods' => [ + 'fixture' => 'qdc_skosmos.xml', + 'enrichmentFixture' => 'Enrichment/skosmos_results.json', + 'config' => [], + 'expected' => [ + 'topic_add_txt_mv' => [], + ], + ]; + yield 'Forward without enrichment methods' => [ + 'fixture' => 'forward_skosmos.xml', + 'enrichmentFixture' => 'Enrichment/skosmos_results.json', + 'config' => [], + 'expected' => [ + 'topic_add_txt_mv' => [], + ], + ]; + } + + /** + * Test Skosmos enrichment + * + * @param string $fixture Fixture filename + * @param string|null $enrichmentFixture Enrichment data fixture filename + * @param array $config Custom config + * @param array $expected Expected results + * + * @return void + */ + #[\PHPUnit\Framework\Attributes\DataProvider('getSkosmosEnrichmentData')] + public function testSkosmosEnrichment( + string $fixture, + ?string $enrichmentFixture, + array $config, + array $expected, + ): void { + $httpService = $this->createMock(HttpService::class); + $record = match (true) { + str_starts_with($fixture, 'marc_authority_') => + $this->createMarcRecord(MarcAuthority::class, $fixture, []), + str_starts_with($fixture, 'marc_') => + $this->createMarcRecord(Marc::class, $fixture, []), + str_starts_with($fixture, 'ead3_') => + $this->createRecord( + \RecordManager\Base\Record\Ead3::class, + $fixture, + constructorParams: [$httpService] + ), + str_starts_with($fixture, 'lido_') => + $this->createRecord( + \RecordManager\Base\Record\Lido::class, + $fixture, + constructorParams: [$httpService] + ), + str_starts_with($fixture, 'qdc_') => + $this->createRecord( + \RecordManager\Base\Record\Qdc::class, + $fixture, + constructorParams: [$httpService] + ), + str_starts_with($fixture, 'forward_') => + $this->createRecord( + \RecordManager\Base\Record\Forward::class, + $fixture, + [] + ), + default => null, + }; + + $record->normalize(); + $fields = $record->toSolrArray(); + + $dbEntities = []; + if ($enrichmentFixture) { + $enrichmentData = $this->getFixture($enrichmentFixture); + $dbEntities = json_decode($enrichmentData, true); + } + + $enricher = $this->getSkosmosEnricher($dbEntities, $config); + $enricher->enrich('test', $record, $fields); + + foreach ($expected as $field => $values) { + if ($values === 'notEmpty') { + $this->assertNotEmpty($fields[$field] ?? []); + } elseif ($values === 'isEmpty') { + $this->assertEmpty($fields[$field] ?? []); + } elseif (is_array($values)) { + $this->assertEquals($values, $fields[$field] ?? []); + } else { + $this->assertEquals($values, $fields[$field] ?? null); + } + } + } + + /** + * Get a Skosmos enrichment object + * + * @param array $dbEntities Database entities + * @param array $config Main config + * + * @return SkosmosEnrichment + */ + protected function getSkosmosEnricher(array $dbEntities, array $config = []): SkosmosEnrichment + { + if (empty($config)) { + $config = [ + 'SkosmosEnrichment' => [ + 'base_url' => 'http://test.skosmos.url', + 'url_prefix_allowed_list' => ['http://www.yso.fi/onto/yso/'], + 'uri_prefix_exact_matches' => ['http://www.yso.fi/onto/yso/'], + 'solr_location_field' => 'location_geo', + 'solr_center_field' => 'center_coords', + ], + ]; + } + + $db = $this->createMock( + \RecordManager\Base\Database\MongoDatabase::class, + ); + + foreach ($dbEntities as &$entity) { + if (isset($entity['data']) && is_array($entity['data'])) { + $entity['data'] = serialize(\ML\JsonLD\JsonLD::getDocument(json_encode($entity['data']))); + } + } + unset($entity); + + $db->expects($this->any())->method('findLinkedDataEnrichment') + ->willReturnCallback(function ($params) use ($dbEntities) { + return $dbEntities[$params['_id']] ?? null; + }); + + $db->expects($this->any())->method('saveLinkedDataEnrichment') + ->willReturn(true); + + $metadataUtils = $this->getMockBuilder(MetadataUtils::class) + ->onlyMethods([]) + ->disableOriginalConstructor() + ->getMock(); + + $enricher = $this->getMockBuilder(SkosmosEnrichment::class) + ->onlyMethods([]) + ->setConstructorArgs([ + $config, + $db, + $this->createMock(Logger::class), + $this->createMock(PluginManager::class), + $this->createMock(HttpService::class), + $metadataUtils, + ]) + ->getMock(); + + return $enricher; + } +} diff --git a/tests/fixtures/Base/Enrichment/skosmos_author_results.json b/tests/fixtures/Base/Enrichment/skosmos_author_results.json new file mode 100644 index 000000000..43ad4f106 --- /dev/null +++ b/tests/fixtures/Base/Enrichment/skosmos_author_results.json @@ -0,0 +1,14 @@ +{ + "http://www.yso.fi/onto/yso/p99999": { + "_id": "http://www.yso.fi/onto/yso/p99999", + "data": { + "prefLabel": { + "en": "Enriched Author Name", + "fi": "Rikastettu tekijän nimi" + }, + "altLabel": { + "en": "Author Variant" + } + } + } +} diff --git a/tests/fixtures/Base/Enrichment/skosmos_authority_results.json b/tests/fixtures/Base/Enrichment/skosmos_authority_results.json new file mode 100644 index 000000000..a1aa812cc --- /dev/null +++ b/tests/fixtures/Base/Enrichment/skosmos_authority_results.json @@ -0,0 +1,25 @@ +{ + "http://www.yso.fi/onto/yso/p11111": { + "_id": "http://www.yso.fi/onto/yso/p11111", + "data": { + "@context": { + "skos": "http://www.w3.org/2004/02/skos/core#", + "uri": "@id", + "type": "@type", + "lang": "@language", + "value": "@value", + "graph": "@graph", + "prefLabel": "skos:prefLabel" + }, + "graph": [ + { + "uri": "http://www.yso.fi/onto/yso/p11111", + "type": "skos:Concept", + "prefLabel": [ + {"lang": "en", "value": "Test Occupation"} + ] + } + ] + } + } +} diff --git a/tests/fixtures/Base/Enrichment/skosmos_exactmatch_results.json b/tests/fixtures/Base/Enrichment/skosmos_exactmatch_results.json new file mode 100644 index 000000000..4fbac5601 --- /dev/null +++ b/tests/fixtures/Base/Enrichment/skosmos_exactmatch_results.json @@ -0,0 +1,25 @@ +{ + "http://www.yso.fi/onto/yso/p22222": { + "_id": "http://www.yso.fi/onto/yso/p22222", + "data": { + "@context": { + "skos": "http://www.w3.org/2004/02/skos/core#", + "uri": "@id", + "type": "@type", + "lang": "@language", + "value": "@value", + "graph": "@graph", + "prefLabel": "skos:prefLabel" + }, + "graph": [ + { + "uri": "http://www.yso.fi/onto/yso/p22222", + "type": "skos:Concept", + "prefLabel": [ + {"lang": "en", "value": "Exact Match Enhanced Topic"} + ] + } + ] + } + } +} diff --git a/tests/fixtures/Base/Enrichment/skosmos_excluded_location_results.json b/tests/fixtures/Base/Enrichment/skosmos_excluded_location_results.json new file mode 100644 index 000000000..57a95c6a3 --- /dev/null +++ b/tests/fixtures/Base/Enrichment/skosmos_excluded_location_results.json @@ -0,0 +1,28 @@ +{ + "http://www.yso.fi/onto/yso/p44444": { + "_id": "http://www.yso.fi/onto/yso/p44444", + "data": { + "@context": { + "skos": "http://www.w3.org/2004/02/skos/core#", + "wgs84": "http://www.w3.org/2003/01/geo/wgs84_pos#", + "uri": "@id", + "type": "@type", + "lang": "@language", + "value": "@value", + "graph": "@graph", + "prefLabel": "skos:prefLabel" + }, + "graph": [ + { + "uri": "http://www.yso.fi/onto/yso/p44444", + "type": "skos:Concept", + "prefLabel": [ + {"lang": "en", "value": "Excluded Location"} + ], + "wgs84:lat": "61.4978", + "wgs84:long": "23.7610" + } + ] + } + } +} diff --git a/tests/fixtures/Base/Enrichment/skosmos_geographic_results.json b/tests/fixtures/Base/Enrichment/skosmos_geographic_results.json new file mode 100644 index 000000000..9cc99d9a7 --- /dev/null +++ b/tests/fixtures/Base/Enrichment/skosmos_geographic_results.json @@ -0,0 +1,14 @@ +{ + "http://www.yso.fi/onto/yso/p94426": { + "_id": "http://www.yso.fi/onto/yso/p94426", + "data": { + "prefLabel": { + "en": "Helsinki", + "fi": "Helsinki", + "sv": "Helsingfors" + }, + "latitude": "60.1699", + "longitude": "24.9384" + } + } +} diff --git a/tests/fixtures/Base/Enrichment/skosmos_multilang_results.json b/tests/fixtures/Base/Enrichment/skosmos_multilang_results.json new file mode 100644 index 000000000..b8971af8b --- /dev/null +++ b/tests/fixtures/Base/Enrichment/skosmos_multilang_results.json @@ -0,0 +1,28 @@ +{ + "http://www.yso.fi/onto/yso/p33333": { + "_id": "http://www.yso.fi/onto/yso/p33333", + "data": { + "@context": { + "skos": "http://www.w3.org/2004/02/skos/core#", + "uri": "@id", + "type": "@type", + "lang": "@language", + "value": "@value", + "graph": "@graph", + "prefLabel": "skos:prefLabel" + }, + "graph": [ + { + "uri": "http://www.yso.fi/onto/yso/p33333", + "type": "skos:Concept", + "prefLabel": [ + {"lang": "en", "value": "Multilingual Topic English"}, + {"lang": "fi", "value": "Monikielinen aihe suomeksi"}, + {"lang": "sv", "value": "Flerspråkigt ämne på svenska"}, + {"lang": "de", "value": "Mehrsprachiges Thema auf Deutsch"} + ] + } + ] + } + } +} diff --git a/tests/fixtures/Base/Enrichment/skosmos_results.json b/tests/fixtures/Base/Enrichment/skosmos_results.json new file mode 100644 index 000000000..0587e6329 --- /dev/null +++ b/tests/fixtures/Base/Enrichment/skosmos_results.json @@ -0,0 +1,84 @@ +{ + "http://www.yso.fi/onto/yso/p12345": { + "_id": "http://www.yso.fi/onto/yso/p12345", + "data": { + "@context": { + "skos": "http://www.w3.org/2004/02/skos/core#", + "uri": "@id", + "type": "@type", + "lang": "@language", + "value": "@value", + "graph": "@graph", + "prefLabel": "skos:prefLabel", + "altLabel": "skos:altLabel" + }, + "graph": [ + { + "uri": "http://www.yso.fi/onto/yso/p12345", + "type": "skos:Concept", + "prefLabel": [ + {"lang": "en", "value": "Enhanced Topic"}, + {"lang": "sv", "value": "Förbättrat ämne"} + ], + "altLabel": [ + {"lang": "en", "value": "Alternative Topic"} + ] + } + ] + } + }, + "http://www.yso.fi/onto/yso/p94426": { + "_id": "http://www.yso.fi/onto/yso/p94426", + "data": { + "@context": { + "skos": "http://www.w3.org/2004/02/skos/core#", + "wgs84": "http://www.w3.org/2003/01/geo/wgs84_pos#", + "uri": "@id", + "type": "@type", + "lang": "@language", + "value": "@value", + "graph": "@graph", + "prefLabel": "skos:prefLabel" + }, + "graph": [ + { + "uri": "http://www.yso.fi/onto/yso/p94426", + "type": "skos:Concept", + "prefLabel": [ + {"lang": "en", "value": "Helsinki"}, + {"lang": "sv", "value": "Helsingfors"} + ], + "wgs84:lat": "60.1699", + "wgs84:long": "24.9384" + } + ] + } + }, + "http://www.yso.fi/onto/yso/p99999": { + "_id": "http://www.yso.fi/onto/yso/p99999", + "data": { + "@context": { + "skos": "http://www.w3.org/2004/02/skos/core#", + "uri": "@id", + "type": "@type", + "lang": "@language", + "value": "@value", + "graph": "@graph", + "prefLabel": "skos:prefLabel", + "altLabel": "skos:altLabel" + }, + "graph": [ + { + "uri": "http://www.yso.fi/onto/yso/p99999", + "type": "skos:Concept", + "prefLabel": [ + {"lang": "en", "value": "Enriched Author Name"} + ], + "altLabel": [ + {"lang": "en", "value": "Author Variant"} + ] + } + ] + } + } +} diff --git a/tests/fixtures/Base/record/ead3_skosmos.xml b/tests/fixtures/Base/record/ead3_skosmos.xml new file mode 100644 index 000000000..ade41c60f --- /dev/null +++ b/tests/fixtures/Base/record/ead3_skosmos.xml @@ -0,0 +1,23 @@ + + + + ead3-test-001 + + + Test EAD3 Document with Skosmos Subject + ead3-test-001 + + + Test Repository + + + + + + Test Subject + + + +

This is a test EAD3 document for Skosmos enrichment testing.

+
+
diff --git a/tests/fixtures/Base/record/forward_skosmos.xml b/tests/fixtures/Base/record/forward_skosmos.xml new file mode 100644 index 000000000..076e16c98 --- /dev/null +++ b/tests/fixtures/Base/record/forward_skosmos.xml @@ -0,0 +1,17 @@ + + + + forward-test-001 + + Test Archive + + + <TitleText>Test Forward Document</TitleText> + <TitleRelationship>original</TitleRelationship> + + Test Forward Document + + Test Subject + + + diff --git a/tests/fixtures/Base/record/lido_skosmos.xml b/tests/fixtures/Base/record/lido_skosmos.xml new file mode 100644 index 000000000..fe6dd5a68 --- /dev/null +++ b/tests/fixtures/Base/record/lido_skosmos.xml @@ -0,0 +1,44 @@ + + + + lido-test-001 + + + + + Test LIDO Document with Skosmos Subject + + + + + + + Test Museum + + + + + + + + + + + http://www.yso.fi/onto/yso/p12345 + Test Subject + + + + + + + + + lido-test-001 + + Archive + + + + + diff --git a/tests/fixtures/Base/record/marc_authority_skosmos.xml b/tests/fixtures/Base/record/marc_authority_skosmos.xml new file mode 100644 index 000000000..5170f692b --- /dev/null +++ b/tests/fixtures/Base/record/marc_authority_skosmos.xml @@ -0,0 +1,16 @@ + + + 00000nz a2200000n 4500 + authority_skosmos_test + 20251215000000.0 + 251215n| azannaabn |a aaa + + Test Authority Name + + + Test Occupation + http://www.yso.fi/onto/yso/p11111 + yso + + + diff --git a/tests/fixtures/Base/record/marc_skosmos_1.xml b/tests/fixtures/Base/record/marc_skosmos_1.xml new file mode 100644 index 000000000..a0f25306f --- /dev/null +++ b/tests/fixtures/Base/record/marc_skosmos_1.xml @@ -0,0 +1,19 @@ + + + 01195cam a22004094i 4500 + skosmos_test_1 + 20251215000000.0 + 251215s2025 fi 000 0 fin d + + Test Author. + + + Test Title for Skosmos Enrichment + + + Test Topic + http://www.yso.fi/onto/yso/p12345 + yso + + + diff --git a/tests/fixtures/Base/record/marc_skosmos_2.xml b/tests/fixtures/Base/record/marc_skosmos_2.xml new file mode 100644 index 000000000..5c4bfeb5c --- /dev/null +++ b/tests/fixtures/Base/record/marc_skosmos_2.xml @@ -0,0 +1,19 @@ + + + 01195cam a22004094i 4500 + skosmos_test_2 + 20251215000000.0 + 251215s2025 fi 000 0 fin d + + Test Author. + + + Test Title for Geographic Enrichment + + + Test Geographic Place + http://www.yso.fi/onto/yso/p94426 + yso + + + diff --git a/tests/fixtures/Base/record/marc_skosmos_3.xml b/tests/fixtures/Base/record/marc_skosmos_3.xml new file mode 100644 index 000000000..c8540e7f3 --- /dev/null +++ b/tests/fixtures/Base/record/marc_skosmos_3.xml @@ -0,0 +1,15 @@ + + + 01195cam a22004094i 4500 + skosmos_test_3 + 20251215000000.0 + 251215s2025 fi 000 0 fin d + + Test Author + http://www.yso.fi/onto/yso/p99999 + + + Test Title for Author Enrichment + + + diff --git a/tests/fixtures/Base/record/marc_skosmos_exactmatch.xml b/tests/fixtures/Base/record/marc_skosmos_exactmatch.xml new file mode 100644 index 000000000..de3d0a00d --- /dev/null +++ b/tests/fixtures/Base/record/marc_skosmos_exactmatch.xml @@ -0,0 +1,19 @@ + + + 01195cam a22004094i 4500 + skosmos_test_exactmatch + 20251215000000.0 + 251215s2025 fi 000 0 fin d + + Test Author. + + + Test Title for Exact Match + + + Exact Match Topic + http://www.yso.fi/onto/yso/p22222 + yso + + + diff --git a/tests/fixtures/Base/record/marc_skosmos_excluded_location.xml b/tests/fixtures/Base/record/marc_skosmos_excluded_location.xml new file mode 100644 index 000000000..e7cd9f7ec --- /dev/null +++ b/tests/fixtures/Base/record/marc_skosmos_excluded_location.xml @@ -0,0 +1,19 @@ + + + 01195cam a22004094i 4500 + skosmos_test_excluded + 20251215000000.0 + 251215s2025 fi 000 0 fin d + + Test Author. + + + Test Title for Excluded Location + + + Excluded Location + http://www.yso.fi/onto/yso/p44444 + yso + + + diff --git a/tests/fixtures/Base/record/marc_skosmos_invalid_uri.xml b/tests/fixtures/Base/record/marc_skosmos_invalid_uri.xml new file mode 100644 index 000000000..21cf3c20f --- /dev/null +++ b/tests/fixtures/Base/record/marc_skosmos_invalid_uri.xml @@ -0,0 +1,19 @@ + + + 01195cam a22004094i 4500 + skosmos_test_invalid + 20251215000000.0 + 251215s2025 fi 000 0 fin d + + Test Author. + + + Test Title with Invalid URI + + + Test Topic + http://invalid.uri.example.com/p12345 + other + + + diff --git a/tests/fixtures/Base/record/marc_skosmos_multilang.xml b/tests/fixtures/Base/record/marc_skosmos_multilang.xml new file mode 100644 index 000000000..d2bd4731a --- /dev/null +++ b/tests/fixtures/Base/record/marc_skosmos_multilang.xml @@ -0,0 +1,19 @@ + + + 01195cam a22004094i 4500 + skosmos_test_multilang + 20251215000000.0 + 251215s2025 fi 000 0 fin d + + Test Author. + + + Test Title for Multilingual + + + Multilang Topic + http://www.yso.fi/onto/yso/p33333 + yso + + + diff --git a/tests/fixtures/Base/record/qdc_skosmos.xml b/tests/fixtures/Base/record/qdc_skosmos.xml new file mode 100644 index 000000000..95bb09796 --- /dev/null +++ b/tests/fixtures/Base/record/qdc_skosmos.xml @@ -0,0 +1,9 @@ + + + Test QDC Document + Test Subject + This is a test QDC document for Skosmos enrichment testing. + Text + qdc-test-001 + From c3862d0b8bcf21ab7c3b69ca8086e0d9342ad421 Mon Sep 17 00:00:00 2001 From: Juha Luoma Date: Mon, 15 Dec 2025 14:01:54 +0200 Subject: [PATCH 05/13] Adjusted null value test --- .../Base/Enrichment/SkosmosEnrichmentTest.php | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/tests/RecordManagerTest/Base/Enrichment/SkosmosEnrichmentTest.php b/tests/RecordManagerTest/Base/Enrichment/SkosmosEnrichmentTest.php index c6e0e195d..d88c60c3e 100644 --- a/tests/RecordManagerTest/Base/Enrichment/SkosmosEnrichmentTest.php +++ b/tests/RecordManagerTest/Base/Enrichment/SkosmosEnrichmentTest.php @@ -83,8 +83,6 @@ public static function getSkosmosEnrichmentData(): Generator 'enrichmentFixture' => 'Enrichment/skosmos_results.json', 'config' => [], 'expected' => [ - // Marc class doesn't have getAuthorIds() method, so enrichment won't occur - // Author field remains unchanged from the MARC record 'author' => ['Test Author'], ], ]; @@ -103,7 +101,7 @@ public static function getSkosmosEnrichmentData(): Generator 'enrichmentFixture' => null, 'config' => [], 'expected' => [ - 'topic_add_txt_mv' => [], + 'topic_add_txt_mv' => null, ], ]; yield 'exact match enrichment' => [ @@ -162,7 +160,7 @@ public static function getSkosmosEnrichmentData(): Generator 'enrichmentFixture' => 'Enrichment/skosmos_results.json', 'config' => [], 'expected' => [ - 'topic_add_txt_mv' => [], + 'topic_add_txt_mv' => null, ], ]; yield 'Forward without enrichment methods' => [ @@ -170,7 +168,7 @@ public static function getSkosmosEnrichmentData(): Generator 'enrichmentFixture' => 'Enrichment/skosmos_results.json', 'config' => [], 'expected' => [ - 'topic_add_txt_mv' => [], + 'topic_add_txt_mv' => null, ], ]; } @@ -238,15 +236,7 @@ public function testSkosmosEnrichment( $enricher->enrich('test', $record, $fields); foreach ($expected as $field => $values) { - if ($values === 'notEmpty') { - $this->assertNotEmpty($fields[$field] ?? []); - } elseif ($values === 'isEmpty') { - $this->assertEmpty($fields[$field] ?? []); - } elseif (is_array($values)) { - $this->assertEquals($values, $fields[$field] ?? []); - } else { - $this->assertEquals($values, $fields[$field] ?? null); - } + $this->assertEquals($values, $fields[$field] ?? null); } } From ce665ad1302092c338b7f9f19a258d6497ca87f9 Mon Sep 17 00:00:00 2001 From: Juha Luoma Date: Tue, 16 Dec 2025 11:10:45 +0200 Subject: [PATCH 06/13] Added authenrichmenttest, added mapping enum to handle enrichment name mapping --- .../Base/Enrichment/AuthEnrichment.php | 23 +- .../Base/Enrichment/EnrichmentMapping.php | 64 ++++++ .../Base/Enrichment/SkosmosEnrichment.php | 25 +-- src/RecordManager/Base/Solr/SolrUpdater.php | 38 +--- .../Base/Enrichment/AuthEnrichmentTest.php | 206 ++++++++++++++++++ tests/fixtures/Base/record/marc_auth_1.xml | 19 ++ .../record/marc_auth_missing_authority.xml | 19 ++ .../fixtures/Base/record/marc_auth_no_ids.xml | 17 ++ .../fixtures/Base/record/marc_authority_1.xml | 17 ++ 9 files changed, 370 insertions(+), 58 deletions(-) create mode 100644 src/RecordManager/Base/Enrichment/EnrichmentMapping.php create mode 100644 tests/RecordManagerTest/Base/Enrichment/AuthEnrichmentTest.php create mode 100644 tests/fixtures/Base/record/marc_auth_1.xml create mode 100644 tests/fixtures/Base/record/marc_auth_missing_authority.xml create mode 100644 tests/fixtures/Base/record/marc_auth_no_ids.xml create mode 100644 tests/fixtures/Base/record/marc_authority_1.xml diff --git a/src/RecordManager/Base/Enrichment/AuthEnrichment.php b/src/RecordManager/Base/Enrichment/AuthEnrichment.php index 7595feae5..98c5455a7 100644 --- a/src/RecordManager/Base/Enrichment/AuthEnrichment.php +++ b/src/RecordManager/Base/Enrichment/AuthEnrichment.php @@ -107,8 +107,16 @@ public function __construct( */ public function enrich($sourceId, $record, &$solrArray) { - if ($record instanceof \RecordManager\Base\Record\Marc) { - $this->enrichMarcRecord($sourceId, $record, $solrArray); + foreach ($solrArray['author2_id_str_mv'] ?? [] as $id) { + $this->enrichField( + $sourceId, + $record, + $solrArray, + $id, + 'author_variant', + 'author_variant', + true + ); } } @@ -124,17 +132,6 @@ public function enrich($sourceId, $record, &$solrArray) */ public function enrichMarcRecord($sourceId, $record, &$solrArray): void { - foreach ($solrArray['author2_id_str_mv'] ?? [] as $id) { - $this->enrichField( - $sourceId, - $record, - $solrArray, - $id, - 'author_variant', - 'author_variant', - true - ); - } } /** diff --git a/src/RecordManager/Base/Enrichment/EnrichmentMapping.php b/src/RecordManager/Base/Enrichment/EnrichmentMapping.php new file mode 100644 index 000000000..542f5fd59 --- /dev/null +++ b/src/RecordManager/Base/Enrichment/EnrichmentMapping.php @@ -0,0 +1,64 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/NatLibFi/RecordManager + */ + +namespace RecordManager\Base\Enrichment; + +/** + * Enrichment mapping enum + * + * @category DataManagement + * @package RecordManager + * @author Juha Luoma + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/NatLibFi/RecordManager + */ +enum EnrichmentMapping: string +{ + case SKOSMOS_ENRICHMENT = 'SkosmosEnrichment'; + case AUTH_ENRICHMENT = 'AuthEnrichment'; + + /** + * Get name of the enrichment from string. This function handles legacy names. + * + * @param string $value Value + * + * @return string Mapped value or original value + */ + public static function fromString(string $value): string + { + + $valueToLower = strtolower($value); + return match (true) { + str_ends_with($valueToLower, 'skosmosenrichment') => self::SKOSMOS_ENRICHMENT->value, + str_ends_with($valueToLower, 'onkilightenrichment') => self::SKOSMOS_ENRICHMENT->value, + str_ends_with($valueToLower, 'authenrichment') => self::AUTH_ENRICHMENT->value, + default => $value, + }; + } +} diff --git a/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php b/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php index 0c95a3e2b..d51629a76 100644 --- a/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php +++ b/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php @@ -74,14 +74,14 @@ class SkosmosEnrichment extends AbstractEnrichment * * @var string */ - protected $apiBaseURL; + protected string $apiBaseURL; /** * List of allowed URL prefixes to try to fetch * * @var array */ - protected $urlPrefixAllowedList; + protected array $urlPrefixAllowedList; /** * List of URI prefixes for which to process other vocabularies with @@ -89,52 +89,52 @@ class SkosmosEnrichment extends AbstractEnrichment * * @var array */ - protected $uriPrefixExactMatches; + protected array $uriPrefixExactMatches; /** * Solr field to use for the location data * * @var string */ - protected $solrLocationField = ''; + protected string $solrLocationField = ''; /** * Solr field to use for the center coordinates of locations * * @var string */ - protected $solrCenterField = ''; + protected string $solrCenterField = ''; /** * Languages to allow * * @var array */ - protected $languages = []; + protected array $languages = []; /** * Cache for recent records * * @var ?\cash\LRUCache */ - protected $recordCache = null; + protected ?\cash\LRUCache $recordCache = null; /** * Cache for recent enrichment results * * @var ?\cash\LRUCache */ - protected $enrichmentCache = null; + protected ?\cash\LRUCache $enrichmentCache = null; /** - * Default fields to enrich. Key is the method in driver and value is array + * Enrichment specifications. Key is the method in driver and value is array * - pref, preferred field in solr * - alt, alternative field in solr * - check, check field for existing values * * @var array */ - protected $defaultFields = [ + protected array $enrichmentSpecs = [ 'getRawTopicIds' => [ 'pref' => 'topic_add_txt_mv', 'alt' => 'topic_alt_txt_mv', @@ -170,7 +170,7 @@ class SkosmosEnrichment extends AbstractEnrichment * * @var array */ - protected $excludedLocationMatches = []; + protected array $excludedLocationMatches = []; /** * Initialize settings @@ -213,7 +213,6 @@ public function init() if ($cacheSize = $settings['enrichment_cache_size'] ?? 10000) { $this->enrichmentCache = new \cash\LRUCache((int)$cacheSize); } - foreach ((array)($settings['excluded_location_matches'] ?? []) as $type => $file) { $listFile = RECMAN_BASE_PATH . "/conf/$file"; $ids = file($listFile, FILE_IGNORE_NEW_LINES); @@ -284,7 +283,7 @@ protected function enrichAuthorityRecord($sourceId, $record, &$solrArray): void */ protected function enrichRecord($sourceId, $record, &$solrArray): void { - foreach ($this->defaultFields as $method => $spec) { + foreach ($this->enrichmentSpecs as $method => $spec) { if (!is_callable([$record, $method])) { continue; } diff --git a/src/RecordManager/Base/Solr/SolrUpdater.php b/src/RecordManager/Base/Solr/SolrUpdater.php index e310b7612..6a759cc9a 100644 --- a/src/RecordManager/Base/Solr/SolrUpdater.php +++ b/src/RecordManager/Base/Solr/SolrUpdater.php @@ -31,6 +31,7 @@ use GuzzleHttp\Client; use RecordManager\Base\Database\DatabaseInterface as Database; +use RecordManager\Base\Enrichment\EnrichmentMapping; use RecordManager\Base\Enrichment\PluginManager as EnrichmentPluginManager; use RecordManager\Base\Exception\HttpRequestException; use RecordManager\Base\Http\HttpService as HttpService; @@ -3107,39 +3108,12 @@ protected function enrich($source, $settings, $record, &$data, $stage = '') $dsEnrichments = (array)($settings['enrichments'] ?? []); $enrichments = array_unique( array_map( - /** - * Bc support: map all instances of recordOnkiLightEnrichment and recordSkosmosEnrichment to - * use SkosmosEnrichment instead and recordAuthEnrichment instances - * to use AuthEnrichment instead. - * - * This will help to map all instances under the same key. - */ function ($enrichment) { + $exploded = explode(',', $enrichment, 2); - $enrichmentName = $exploded[0]; - $enrichmentStage = $exploded[1] ?? ''; - if (!$enrichment[0]) { - return []; - } - if ( - str_ends_with($enrichmentName, 'OnkiLightEnrichment') - || str_ends_with($enrichmentName, 'SkosmosEnrichment') - ) { - return [ - 'name' => 'SkosmosEnrichment', - 'stage' => $enrichmentStage, - ]; - } - if (str_ends_with($enrichmentName, 'AuthEnrichment')) { - return [ - 'name' => 'AuthEnrichment', - 'stage' => $enrichmentStage, - ]; - } - return [ - 'name' => $enrichmentName, - 'stage' => $enrichmentStage, - ]; + $name = EnrichmentMapping::fromString($exploded[0]); + $stage = $exploded[1] ?? ''; + return compact('name', 'stage'); }, [ ...$globalEnrichments, @@ -3149,7 +3123,7 @@ function ($enrichment) { SORT_REGULAR ); foreach ($enrichments as $enrichment) { - if (!$enrichment || $stage !== $enrichment['stage']) { + if ($stage !== $enrichment['stage']) { continue; } $enrichmentName = $enrichment['name']; diff --git a/tests/RecordManagerTest/Base/Enrichment/AuthEnrichmentTest.php b/tests/RecordManagerTest/Base/Enrichment/AuthEnrichmentTest.php new file mode 100644 index 000000000..fe1ebc2ac --- /dev/null +++ b/tests/RecordManagerTest/Base/Enrichment/AuthEnrichmentTest.php @@ -0,0 +1,206 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/NatLibFi/RecordManager + */ + +namespace RecordManagerTest\Base\Enrichment; + +use Generator; +use RecordManager\Base\Enrichment\AuthEnrichment; +use RecordManager\Base\Http\HttpService; +use RecordManager\Base\Record\Marc; +use RecordManager\Base\Record\PluginManager; +use RecordManager\Base\Utils\Logger; +use RecordManager\Base\Utils\MetadataUtils; +use RecordManagerTest\Base\Record\RecordTestBase; + +/** + * Auth enrichment test class + * + * @category DataManagement + * @package RecordManager + * @author Juha Luoma + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/NatLibFi/RecordManager + */ +class AuthEnrichmentTest extends RecordTestBase +{ + /** + * Data provider for testing Auth enrichment + * + * @return Generator + */ + public static function getAuthEnrichmentData(): Generator + { + yield 'basic author enrichment' => [ + 'fixture' => 'marc_auth_1.xml', + 'authorityRecords' => [ + '(FIN11)authority_001' => 'marc_authority_1.xml', + ], + 'config' => [], + 'authorIds' => ['(FIN11)authority_001'], + 'expected' => [ + 'author_variant' => ['p a pa', 'Alternative Name 1', 'Alternative Name 2'], + ], + ]; + yield 'no author IDs' => [ + 'fixture' => 'marc_auth_no_ids.xml', + 'authorityRecords' => [], + 'config' => [], + 'authorIds' => [], + 'expected' => [ + 'author2' => ['Second Author Without ID'], + ], + ]; + yield 'missing authority record' => [ + 'fixture' => 'marc_auth_missing_authority.xml', + 'authorityRecords' => [], + 'config' => [], + 'authorIds' => ['(FIN11)nonexistent_authority', '(FIN11)another_missing'], + 'expected' => [ + 'author2' => ['Secondary Author With Missing Authority'], + ], + ]; + } + + /** + * Test Auth enrichment + * + * @param string $fixture Fixture filename + * @param array $authorityRecords Authority record fixtures (id => filename) + * @param array $config Custom config + * @param array $authorIds Author IDs to add to author2_id_str_mv + * @param array $expected Expected results + * + * @return void + */ + #[\PHPUnit\Framework\Attributes\DataProvider('getAuthEnrichmentData')] + public function testAuthEnrichment( + string $fixture, + array $authorityRecords, + array $config, + array $authorIds, + array $expected + ): void { + $record = $this->createMarcRecord(Marc::class, $fixture, []); + $record->normalize(); + $fields = $record->toSolrArray(); + + // Add author IDs to the solr array (simulating what would be there in production) + if (!empty($authorIds)) { + $fields['author2_id_str_mv'] = $authorIds; + } + + $enricher = $this->getAuthEnricher($authorityRecords, $config); + $enricher->enrich('test', $record, $fields); + + foreach ($expected as $key => $value) { + $this->assertEquals($value, $fields[$key] ?? null, "Field '$key' did not match expected value."); + } + } + + /** + * Get an Auth enrichment object + * + * @param array $authorityRecords Authority record fixtures + * @param array $config Main config + * + * @return AuthEnrichment + */ + protected function getAuthEnricher(array $authorityRecords, array $config = []): AuthEnrichment + { + if (empty($config)) { + $config = [ + 'AuthEnrichment' => [ + 'enabled' => true, + ], + ]; + } + + $db = $this->createMock(\RecordManager\Base\Database\DatabaseInterface::class); + $authorityDb = $this->createMock(\RecordManager\Base\Database\DatabaseInterface::class); + + // Mock authority database records + $authorityDbRecords = []; + foreach ($authorityRecords as $id => $filename) { + $authorityRecord = $this->createMarcRecord( + \RecordManager\Base\Record\MarcAuthority::class, + $filename, + [] + ); + $authorityDbRecords[$id] = [ + '_id' => $id, + 'source_id' => 'test', + 'oai_id' => $id, + 'deleted' => false, + 'format' => 'marc', + 'original_data' => $authorityRecord->serialize(), + 'normalized_data' => $authorityRecord->serialize(), + ]; + } + + $authorityDb->expects($this->any()) + ->method('getRecord') + ->willReturnCallback(function ($id) use ($authorityDbRecords) { + return $authorityDbRecords[$id] ?? null; + }); + + $metadataUtils = $this->getMockBuilder(MetadataUtils::class) + ->onlyMethods([]) + ->disableOriginalConstructor() + ->getMock(); + + $recordPluginManager = $this->createMock(PluginManager::class); + $recordPluginManager->expects($this->any()) + ->method('get') + ->willReturnCallback(function ($format) { + if ($format === 'marc') { + return $this->createMarcRecord( + \RecordManager\Base\Record\MarcAuthority::class, + 'marc_authority_1.xml', // Dummy, will be replaced + [] + ); + } + return null; + }); + + $enricher = $this->getMockBuilder(AuthEnrichment::class) + ->onlyMethods([]) + ->setConstructorArgs([ + $config, + $db, + $this->createMock(Logger::class), + $recordPluginManager, + $this->createMock(HttpService::class), + $metadataUtils, + $authorityDb, + ]) + ->getMock(); + + return $enricher; + } +} diff --git a/tests/fixtures/Base/record/marc_auth_1.xml b/tests/fixtures/Base/record/marc_auth_1.xml new file mode 100644 index 000000000..f5d513986 --- /dev/null +++ b/tests/fixtures/Base/record/marc_auth_1.xml @@ -0,0 +1,19 @@ + + + 00000nam a2200000 i 4500 + marc_auth_test_1 + 20251215000000.0 + 251215s2025 fi 000 0 eng d + + Primary Author + (FIN11)authority_001 + + + Test Book Title + + + Secondary Author + (FIN11)authority_001 + + + diff --git a/tests/fixtures/Base/record/marc_auth_missing_authority.xml b/tests/fixtures/Base/record/marc_auth_missing_authority.xml new file mode 100644 index 000000000..62f83cf71 --- /dev/null +++ b/tests/fixtures/Base/record/marc_auth_missing_authority.xml @@ -0,0 +1,19 @@ + + + 00000nam a2200000 i 4500 + marc_auth_test_missing + 20251215000000.0 + 251215s2025 fi 000 0 eng d + + Author With Missing Authority + (FIN11)nonexistent_authority + + + Test Book With Missing Authority + + + Secondary Author With Missing Authority + (FIN11)another_missing + + + diff --git a/tests/fixtures/Base/record/marc_auth_no_ids.xml b/tests/fixtures/Base/record/marc_auth_no_ids.xml new file mode 100644 index 000000000..12b1cf6c7 --- /dev/null +++ b/tests/fixtures/Base/record/marc_auth_no_ids.xml @@ -0,0 +1,17 @@ + + + 00000nam a2200000 i 4500 + marc_auth_test_no_ids + 20251215000000.0 + 251215s2025 fi 000 0 eng d + + Author Without ID + + + Test Book Without Authority IDs + + + Second Author Without ID + + + diff --git a/tests/fixtures/Base/record/marc_authority_1.xml b/tests/fixtures/Base/record/marc_authority_1.xml new file mode 100644 index 000000000..edc9feb62 --- /dev/null +++ b/tests/fixtures/Base/record/marc_authority_1.xml @@ -0,0 +1,17 @@ + + + 00000nz a2200000n 4500 + authority_001 + 20251215000000.0 + 251215n| azannaabn |a aaa + + Primary Author + + + Alternative Name 1 + + + Alternative Name 2 + + + From aa5be10977e4268b5cf3d0599dc0d2209b970b17 Mon Sep 17 00:00:00 2001 From: Juha Luoma Date: Tue, 16 Dec 2025 11:14:35 +0200 Subject: [PATCH 07/13] Removed empty function --- .../Base/Enrichment/AuthEnrichment.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/RecordManager/Base/Enrichment/AuthEnrichment.php b/src/RecordManager/Base/Enrichment/AuthEnrichment.php index 98c5455a7..4b2abdac0 100644 --- a/src/RecordManager/Base/Enrichment/AuthEnrichment.php +++ b/src/RecordManager/Base/Enrichment/AuthEnrichment.php @@ -120,20 +120,6 @@ public function enrich($sourceId, $record, &$solrArray) } } - /** - * Enrich the Marc record and save any additions in solrArray - * - * @param string $sourceId Source ID - * @param object $record Metadata Record - * @param array $solrArray Metadata to be sent to Solr - * - * @throws \Exception - * @return void - */ - public function enrichMarcRecord($sourceId, $record, &$solrArray): void - { - } - /** * Enrich the record and return any additions in solrArray * From 41eb30ad49b14bc5922012654f78818e414b5d47 Mon Sep 17 00:00:00 2001 From: Juha Luoma Date: Tue, 16 Dec 2025 12:15:48 +0200 Subject: [PATCH 08/13] Remove enrichment mapping enum --- .../Base/Enrichment/EnrichmentMapping.php | 64 ------------------- src/RecordManager/Base/Solr/SolrUpdater.php | 10 ++- 2 files changed, 8 insertions(+), 66 deletions(-) delete mode 100644 src/RecordManager/Base/Enrichment/EnrichmentMapping.php diff --git a/src/RecordManager/Base/Enrichment/EnrichmentMapping.php b/src/RecordManager/Base/Enrichment/EnrichmentMapping.php deleted file mode 100644 index 542f5fd59..000000000 --- a/src/RecordManager/Base/Enrichment/EnrichmentMapping.php +++ /dev/null @@ -1,64 +0,0 @@ - - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ - -namespace RecordManager\Base\Enrichment; - -/** - * Enrichment mapping enum - * - * @category DataManagement - * @package RecordManager - * @author Juha Luoma - * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License - * @link https://github.com/NatLibFi/RecordManager - */ -enum EnrichmentMapping: string -{ - case SKOSMOS_ENRICHMENT = 'SkosmosEnrichment'; - case AUTH_ENRICHMENT = 'AuthEnrichment'; - - /** - * Get name of the enrichment from string. This function handles legacy names. - * - * @param string $value Value - * - * @return string Mapped value or original value - */ - public static function fromString(string $value): string - { - - $valueToLower = strtolower($value); - return match (true) { - str_ends_with($valueToLower, 'skosmosenrichment') => self::SKOSMOS_ENRICHMENT->value, - str_ends_with($valueToLower, 'onkilightenrichment') => self::SKOSMOS_ENRICHMENT->value, - str_ends_with($valueToLower, 'authenrichment') => self::AUTH_ENRICHMENT->value, - default => $value, - }; - } -} diff --git a/src/RecordManager/Base/Solr/SolrUpdater.php b/src/RecordManager/Base/Solr/SolrUpdater.php index 3befa2328..f1cd9d81e 100644 --- a/src/RecordManager/Base/Solr/SolrUpdater.php +++ b/src/RecordManager/Base/Solr/SolrUpdater.php @@ -31,7 +31,6 @@ use GuzzleHttp\Client; use RecordManager\Base\Database\DatabaseInterface as Database; -use RecordManager\Base\Enrichment\EnrichmentMapping; use RecordManager\Base\Enrichment\PluginManager as EnrichmentPluginManager; use RecordManager\Base\Exception\HttpRequestException; use RecordManager\Base\Http\HttpService as HttpService; @@ -3141,7 +3140,14 @@ protected function enrich($source, $settings, $record, &$data, $stage = '') function ($enrichment) { $exploded = explode(',', $enrichment, 2); - $name = EnrichmentMapping::fromString($exploded[0]); + $name = strtolower($exploded[0]); + // Legacy support for old enrichment names in configuration + $name = match (true) { + str_ends_with($name, 'skosmosenrichment') => 'SkosmosEnrichment', + str_ends_with($name, 'onkilightenrichment') => 'SkosmosEnrichment', + str_ends_with($name, 'authenrichment') => 'AuthEnrichment', + default => $exploded[0], + }; $stage = $exploded[1] ?? ''; return compact('name', 'stage'); }, From 74dd97bc65a3d9a2f93ccdadba5f0bbd1c4efd39 Mon Sep 17 00:00:00 2001 From: Juha Luoma Date: Tue, 16 Dec 2025 12:38:46 +0200 Subject: [PATCH 09/13] Remove extra space --- src/RecordManager/Base/Solr/SolrUpdater.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/RecordManager/Base/Solr/SolrUpdater.php b/src/RecordManager/Base/Solr/SolrUpdater.php index f1cd9d81e..f32f893d0 100644 --- a/src/RecordManager/Base/Solr/SolrUpdater.php +++ b/src/RecordManager/Base/Solr/SolrUpdater.php @@ -3138,7 +3138,6 @@ protected function enrich($source, $settings, $record, &$data, $stage = '') $enrichments = array_unique( array_map( function ($enrichment) { - $exploded = explode(',', $enrichment, 2); $name = strtolower($exploded[0]); // Legacy support for old enrichment names in configuration From ee41dfbed74a7c015365ca2052f40525bde812e8 Mon Sep 17 00:00:00 2001 From: Juha Luoma Date: Tue, 16 Dec 2025 15:20:46 +0200 Subject: [PATCH 10/13] Adjusted tests to test pluginmanager separately from solrupdater test --- src/RecordManager/Base/Solr/SolrUpdater.php | 32 +++--- .../Base/config/module.config.php | 17 +++ .../Base/Enrichment/PluginManagerTest.php | 106 ++++++++++++++++++ .../Base/Solr/SolrUpdaterTest.php | 47 +++++++- 4 files changed, 178 insertions(+), 24 deletions(-) create mode 100644 tests/RecordManagerTest/Base/Enrichment/PluginManagerTest.php diff --git a/src/RecordManager/Base/Solr/SolrUpdater.php b/src/RecordManager/Base/Solr/SolrUpdater.php index f32f893d0..81c53b005 100644 --- a/src/RecordManager/Base/Solr/SolrUpdater.php +++ b/src/RecordManager/Base/Solr/SolrUpdater.php @@ -3137,23 +3137,16 @@ protected function enrich($source, $settings, $record, &$data, $stage = '') $dsEnrichments = (array)($settings['enrichments'] ?? []); $enrichments = array_unique( array_map( - function ($enrichment) { + function ($enrichment) use ($stage) { $exploded = explode(',', $enrichment, 2); - $name = strtolower($exploded[0]); - // Legacy support for old enrichment names in configuration - $name = match (true) { - str_ends_with($name, 'skosmosenrichment') => 'SkosmosEnrichment', - str_ends_with($name, 'onkilightenrichment') => 'SkosmosEnrichment', - str_ends_with($name, 'authenrichment') => 'AuthEnrichment', - default => $exploded[0], - }; + $name = $exploded[0]; $stage = $exploded[1] ?? ''; return compact('name', 'stage'); }, [ - ...$globalEnrichments, - ...$dsEnrichments, - ] + ...$globalEnrichments, + ...$dsEnrichments, + ] ), SORT_REGULAR ); @@ -3162,14 +3155,15 @@ function ($enrichment) { continue; } $enrichmentName = $enrichment['name']; - if (!isset($this->enrichments[$enrichmentName])) { - if ($enrichmentService = $this->enrichmentPluginManager->get($enrichmentName)) { - $this->enrichments[$enrichmentName] = $enrichmentService; - } else { - continue; - } + if (!$this->enrichmentPluginManager->has($enrichmentName)) { + continue; + } + $enrichmentService = $this->enrichmentPluginManager->get($enrichmentName); + $enrichmentServiceName = $enrichmentService::class; + if (!isset($this->enrichments[$enrichmentServiceName])) { + $this->enrichments[$enrichmentServiceName] = $enrichmentService; } - $this->enrichments[$enrichmentName]->enrich($source, $record, $data); + $this->enrichments[$enrichmentServiceName]->enrich($source, $record, $data); } } diff --git a/src/RecordManager/Base/config/module.config.php b/src/RecordManager/Base/config/module.config.php index 693fb93b1..e2d1daddf 100644 --- a/src/RecordManager/Base/config/module.config.php +++ b/src/RecordManager/Base/config/module.config.php @@ -79,6 +79,23 @@ 'MusicBrainzEnrichment' => \RecordManager\Base\Enrichment\MusicBrainzEnrichment::class, 'NominatimGeocoder' => \RecordManager\Base\Enrichment\NominatimGeocoder::class, 'SkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + + // Legacy aliases: + 'EadOnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'Ead3OnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'LidoOnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'LrmiOnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'MarcAuthOnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'MarcOnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'OnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'EadSkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'Ead3SkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'LidoSkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'LrmiSkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'MarcAuthSkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'MarcSkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + + 'MarcAuthEnrichment' => \RecordManager\Base\Enrichment\AuthEnrichment::class, ], ], 'harvest' => [ diff --git a/tests/RecordManagerTest/Base/Enrichment/PluginManagerTest.php b/tests/RecordManagerTest/Base/Enrichment/PluginManagerTest.php new file mode 100644 index 000000000..80982a2f0 --- /dev/null +++ b/tests/RecordManagerTest/Base/Enrichment/PluginManagerTest.php @@ -0,0 +1,106 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/NatLibFi/RecordManager + */ + +namespace RecordManagerTest\Base\Enrichment; + +use Psr\Container\ContainerInterface; + +/** + * Tests for enrichment plugin manager + * + * @category DataManagement + * @package RecordManager + * @author Juha Luoma + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/NatLibFi/RecordManager + */ +class PluginManagerTest extends \PHPUnit\Framework\TestCase +{ + protected array $moduleConfig = []; + + /** + * Standard setup method. + * + * @return void + */ + public function setUp(): void + { + $this->moduleConfig + = include realpath('./') . '/src/RecordManager/Base/config/module.config.php'; + } + + /** + * Test plugin manager aliases + * + * @return void + */ + public function testAliases(): void + { + $serviceAliases = [ + 'AuthEnrichment', + 'MusicBrainzEnrichment', + 'NominatimGeocoder', + 'SkosmosEnrichment', + 'EadOnkiLightEnrichment', + 'Ead3OnkiLightEnrichment', + 'LidoOnkiLightEnrichment', + 'LrmiOnkiLightEnrichment', + 'MarcAuthOnkiLightEnrichment', + 'MarcOnkiLightEnrichment', + 'OnkiLightEnrichment', + 'EadSkosmosEnrichment', + 'Ead3SkosmosEnrichment', + 'LidoSkosmosEnrichment', + 'LrmiSkosmosEnrichment', + 'MarcAuthSkosmosEnrichment', + 'MarcSkosmosEnrichment', + 'MarcAuthEnrichment', + ]; + $serviceManager = $this->createMock(ContainerInterface::class); + $serviceManager->expects($this->any())->method('get')->willReturnMap( + [ + ['Config', $this->moduleConfig], + ] + ); + $enrichmentPluginManagerFactory = new \RecordManager\Base\ServiceManager\AbstractPluginManagerFactory(); + $enrichmentPluginManager = ($enrichmentPluginManagerFactory)( + $serviceManager, + \RecordManager\Base\Enrichment\PluginManager::class, + ); + $reflectionClass = new \ReflectionClass($enrichmentPluginManager); + $aliasesProperty = $reflectionClass->getProperty('aliases'); + + $aliasesConfig = $this->moduleConfig['recordmanager']['plugin_managers']['enrichment']['aliases'] ?? []; + $aliasesValue = $aliasesProperty->getValue($enrichmentPluginManager); + $this->assertEquals($aliasesConfig, $aliasesValue); + foreach ($serviceAliases as $alias) { + $this->assertTrue($enrichmentPluginManager->has($alias)); + } + } +} diff --git a/tests/RecordManagerTest/Base/Solr/SolrUpdaterTest.php b/tests/RecordManagerTest/Base/Solr/SolrUpdaterTest.php index d7fb477b7..e59499e21 100644 --- a/tests/RecordManagerTest/Base/Solr/SolrUpdaterTest.php +++ b/tests/RecordManagerTest/Base/Solr/SolrUpdaterTest.php @@ -42,6 +42,7 @@ use RecordManager\Base\Solr\SolrUpdater; use RecordManager\Base\Utils\FieldMapper; use RecordManager\Base\Utils\Logger; +use RecordManager\Base\Utils\MetadataUtils; use RecordManager\Base\Utils\WorkerPoolManager; use RecordManagerTest\Base\Feature\FixtureTrait; use RecordManagerTest\Base\Record\CreateSampleRecordTrait; @@ -504,7 +505,7 @@ public function testLegacyEnrichments(): void $solrUpdater->processSingleRecord($dbRecord); $reflectionClass = new ReflectionClass($solrUpdater); $enrichments = array_keys($reflectionClass->getProperty('enrichments')->getValue($solrUpdater)); - $this->assertEquals(['SkosmosEnrichment', 'AuthEnrichment'], $enrichments); + $this->assertEquals([SkosmosEnrichment::class, AuthEnrichment::class], $enrichments); } /** @@ -548,12 +549,48 @@ function ($data) { [], $this->dataSourceConfig ); - $enrichmentMap = [ - ['SkosmosEnrichment', $this->createMock(SkosmosEnrichment::class)], - ['AuthEnrichment', $this->createMock(AuthEnrichment::class)], + $enrichmentTable = [ + 'AuthEnrichment' => \RecordManager\Base\Enrichment\AuthEnrichment::class, + 'MusicBrainzEnrichment' => \RecordManager\Base\Enrichment\MusicBrainzEnrichment::class, + 'NominatimGeocoder' => \RecordManager\Base\Enrichment\NominatimGeocoder::class, + 'SkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + + // Legacy aliases: + 'EadOnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'Ead3OnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'LidoOnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'LrmiOnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'MarcAuthOnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'MarcOnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'OnkiLightEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'EadSkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'Ead3SkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'LidoSkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'LrmiSkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'MarcAuthSkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + 'MarcSkosmosEnrichment' => \RecordManager\Base\Enrichment\SkosmosEnrichment::class, + + 'MarcAuthEnrichment' => \RecordManager\Base\Enrichment\AuthEnrichment::class, ]; $enrichmentPluginManager = $this->createMock(EnrichmentPluginManager::class); - $enrichmentPluginManager->expects($this->any())->method('get')->willReturnMap($enrichmentMap); + $enrichmentPluginManager->expects($this->any())->method('get')->willReturnCallback( + function ($name, $options = null) use ($enrichmentTable) { + return new $enrichmentTable[$name]( + [], + $this->createMock(DatabaseInterface::class), + $this->createMock(Logger::class), + $this->createMock(RecordPluginManager::class), + $this->createMock(HttpService::class), + $this->createMock(MetadataUtils::class), + $this->createMock(DatabaseInterface::class) + ); + } + ); + $enrichmentPluginManager->expects($this->any())->method('has')->willReturnCallback( + function ($name) use ($enrichmentTable) { + return isset($enrichmentTable[$name]); + } + ); $solrUpdater = new SolrUpdater( $this->config, $dsConfig, From 76f2c5017cc032d039a5cb601570dab5cab4092d Mon Sep 17 00:00:00 2001 From: Juha Luoma Date: Tue, 16 Dec 2025 15:21:19 +0200 Subject: [PATCH 11/13] Updated year --- tests/RecordManagerTest/Base/Enrichment/PluginManagerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/RecordManagerTest/Base/Enrichment/PluginManagerTest.php b/tests/RecordManagerTest/Base/Enrichment/PluginManagerTest.php index 80982a2f0..e0c851406 100644 --- a/tests/RecordManagerTest/Base/Enrichment/PluginManagerTest.php +++ b/tests/RecordManagerTest/Base/Enrichment/PluginManagerTest.php @@ -5,7 +5,7 @@ * * PHP version 8 * - * Copyright (C) The National Library of Finland 2020-2023. + * Copyright (C) The National Library of Finland 2025. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, From 50d1c9e7326ad61c37cf999aff57df26043b56d6 Mon Sep 17 00:00:00 2001 From: Juha Luoma Date: Tue, 16 Dec 2025 17:18:27 +0200 Subject: [PATCH 12/13] Use only one enrich spec for skosmos --- .../Base/Enrichment/SkosmosEnrichment.php | 57 +++---------------- 1 file changed, 9 insertions(+), 48 deletions(-) diff --git a/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php b/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php index d51629a76..bcdbc235d 100644 --- a/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php +++ b/src/RecordManager/Base/Enrichment/SkosmosEnrichment.php @@ -160,6 +160,12 @@ class SkosmosEnrichment extends AbstractEnrichment 'alt' => 'author2_variant', 'check' => 'author2', ], + 'getOccupationIds' => [ + 'pref' => 'occupation_str_mv', + 'alt' => '', + 'check' => '', + 'includeInAllFields' => true, + ], ]; /** @@ -225,52 +231,6 @@ public function init() } } - /** - * Enrich the record and return any additions in solrArray - * - * @param string $sourceId Source ID - * @param object $record Metadata Record - * @param array $solrArray Metadata to be sent to Solr - * - * @throws \Exception - * @return void - */ - public function enrich($sourceId, $record, &$solrArray) - { - // Detect if record is an authority record or not as they have different enrichments. - if (str_ends_with($record::class, 'Authority')) { - $this->enrichAuthorityRecord($sourceId, $record, $solrArray); - } else { - $this->enrichRecord($sourceId, $record, $solrArray); - } - } - - /** - * Enrich the authority record and save any additions in solrArray - * - * @param string $sourceId Source ID - * @param object $record Metadata Record - * @param array $solrArray Metadata to be sent to Solr - * - * @throws \Exception - * @return void - */ - protected function enrichAuthorityRecord($sourceId, $record, &$solrArray): void - { - foreach ($record->getOccupationIds() as $id) { - $this->enrichField( - $sourceId, - $record, - $solrArray, - $id, - 'occupation_str_mv', - '', - '', - true - ); - } - } - /** * Enrich the record and save any additions in solrArray * @@ -281,7 +241,7 @@ protected function enrichAuthorityRecord($sourceId, $record, &$solrArray): void * @throws \Exception * @return void */ - protected function enrichRecord($sourceId, $record, &$solrArray): void + public function enrich($sourceId, $record, &$solrArray): void { foreach ($this->enrichmentSpecs as $method => $spec) { if (!is_callable([$record, $method])) { @@ -295,7 +255,8 @@ protected function enrichRecord($sourceId, $record, &$solrArray): void $id, $spec['pref'], $spec['alt'], - $spec['check'] + $spec['check'], + $spec['includeInAllFields'] ?? false ); } } From f4bede2a345b0ea7e40d67e62adeeaa70076071f Mon Sep 17 00:00:00 2001 From: Juha Luoma Date: Tue, 16 Dec 2025 17:23:02 +0200 Subject: [PATCH 13/13] Use only one spec in authenrichment --- .../Base/Enrichment/AuthEnrichment.php | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/RecordManager/Base/Enrichment/AuthEnrichment.php b/src/RecordManager/Base/Enrichment/AuthEnrichment.php index 4b2abdac0..ffa639ef2 100644 --- a/src/RecordManager/Base/Enrichment/AuthEnrichment.php +++ b/src/RecordManager/Base/Enrichment/AuthEnrichment.php @@ -63,6 +63,21 @@ class AuthEnrichment extends AbstractEnrichment */ protected $authorityDb; + /** + * Enrichment specifications. Key is the array in solrArray and value contains following: + * - pref, preferred field in solr + * - check, check field for existing values + * + * @var array + */ + protected array $enrichmentSpecs = [ + 'author2_id_str_mv' => [ + 'pref' => 'author_variant', + 'check' => 'author_variant', + 'includeInAllFields' => true, + ], + ]; + /** * Constructor * @@ -107,16 +122,21 @@ public function __construct( */ public function enrich($sourceId, $record, &$solrArray) { - foreach ($solrArray['author2_id_str_mv'] ?? [] as $id) { - $this->enrichField( - $sourceId, - $record, - $solrArray, - $id, - 'author_variant', - 'author_variant', - true - ); + foreach ($this->enrichmentSpecs as $key => $specs) { + if (empty($solrArray[$key])) { + continue; + } + foreach ($solrArray[$key] as $id) { + $this->enrichField( + $sourceId, + $record, + $solrArray, + $id, + $specs['pref'], + $specs['check'], + $specs['includeInAllFields'] ?? false + ); + } } }