Initial commit
This commit is contained in:
commit
2cdc1fc434
48
Module.php
Normal file
48
Module.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* BIBB Neo Module - Custom VuFind module for BIBB
|
||||
* (Bundesinstitut für Berufsbildung)
|
||||
*
|
||||
* Provides custom RecordDrivers for DSpace and MARC records,
|
||||
* BIBB-specific citation formats, and other customizations.
|
||||
*
|
||||
* @category BIBBNeo
|
||||
* @package Module
|
||||
* @author BIBB
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
|
||||
*/
|
||||
|
||||
namespace BIBBNeo;
|
||||
|
||||
/**
|
||||
* Module definition
|
||||
*/
|
||||
class Module
|
||||
{
|
||||
/**
|
||||
* Get module configuration
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return include __DIR__ . '/config/module.config.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get autoloader configuration
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAutoloaderConfig()
|
||||
{
|
||||
return [
|
||||
'Laminas\Loader\StandardAutoloader' => [
|
||||
'namespaces' => [
|
||||
__NAMESPACE__ => __DIR__ . '/src/BIBBNeo',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
99
README.md
Normal file
99
README.md
Normal file
@ -0,0 +1,99 @@
|
||||
# BIBBNeo Module für VuFind 10.2
|
||||
|
||||
Eigenes VuFind-Modul für das Bundesinstitut für Berufsbildung (BIBB).
|
||||
Ersetzt die bisherigen Core-Modifikationen durch saubere Overrides.
|
||||
|
||||
## Architektur
|
||||
|
||||
```
|
||||
VuFind\RecordDriver\SolrDefault (Core 10.2, unangetastet)
|
||||
│
|
||||
├── VuFind\RecordDriver\SolrMarc (Core 10.2)
|
||||
│ │
|
||||
│ └── BIBBNeo\RecordDriver\SolrMarc
|
||||
│ BIBB-Felder + geänderte Core-Methoden (via Trait)
|
||||
│ Für: Koha-MARC-Records (recordtype = "marc")
|
||||
│
|
||||
└── BIBBNeo\RecordDriver\SolrDspace
|
||||
DSpace-spezifische Methoden + BIBB-Felder (via Trait)
|
||||
Für: DSpace-Records (recordtype = "dspace")
|
||||
```
|
||||
|
||||
### BIBBRecordTrait
|
||||
|
||||
Gemeinsamer PHP-Trait, der von beiden RecordDrivern verwendet wird:
|
||||
|
||||
- **BIBB-Solr-Felder**: citation, citationdr, extend, participation,
|
||||
researchfocus, accompanyingmaterial, additionallinks, dissertationnote,
|
||||
originalversion, reviewof, replaces, isreplacedby, classification,
|
||||
voevzlink, ctrlnum
|
||||
- **Core-Overrides**: getAllSubjectHeadings (nur topic), getFormats
|
||||
(medium vor format), getSeries (series + series2), getContainerVolume
|
||||
(Array-Handling), getSupportedCitationFormats (BIBB, BIBBBWP, APA)
|
||||
|
||||
### SolrDspace (zusätzlich zum Trait)
|
||||
|
||||
- Bitstream-URL-Handling mit VOE-VZ-Link-Zuordnung
|
||||
- DOI/URN-Auflösung
|
||||
- DSpace-Handle-Filterung
|
||||
- Rechte/Embargo-Felder (license, rightslicense, rightsuri, etc.)
|
||||
- getOnlineLinks(), getPids(), getFormatsFiltered()
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. Modul kopieren
|
||||
|
||||
```bash
|
||||
cp -r module/BIBBNeo /usr/local/vufind/module/
|
||||
```
|
||||
|
||||
### 2. Modul aktivieren
|
||||
|
||||
In `/usr/local/vufind/local/httpd-vufind.conf` (oder `env.d/`) die
|
||||
Umgebungsvariable VUFIND_LOCAL_MODULES ergänzen:
|
||||
|
||||
```apache
|
||||
SetEnv VUFIND_LOCAL_MODULES "BIBBNeo"
|
||||
```
|
||||
|
||||
Alternativ in `/usr/local/vufind/local/config/vufind/config.ini`:
|
||||
|
||||
```ini
|
||||
[System]
|
||||
; Falls bereits andere Module aktiv sind, kommasepariert:
|
||||
local_modules = "BIBBNeo"
|
||||
```
|
||||
|
||||
### 3. Cache leeren
|
||||
|
||||
```bash
|
||||
rm -rf /usr/local/vufind/local/cache/configs/*
|
||||
rm -rf /usr/local/vufind/local/cache/objects/*
|
||||
```
|
||||
|
||||
### 4. Apache neustarten
|
||||
|
||||
```bash
|
||||
systemctl restart apache2
|
||||
```
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- Solr-Feld `recordtype` muss für DSpace-Records den Wert `dspace` enthalten
|
||||
- Alle BIBB-spezifischen Solr-Felder müssen im Schema definiert sein
|
||||
|
||||
## Noch zu migrieren
|
||||
|
||||
Die folgenden Dateien aus der alten Installation müssen noch
|
||||
ins BIBBNeo-Modul überführt werden:
|
||||
|
||||
- [ ] Citation.php (BIBB/BWP-Zitierformat)
|
||||
- [ ] KohaILSDI.php (Koha-Treiber-Anpassungen)
|
||||
- [ ] RecordDataFormatterFactory.php (Detailanzeige)
|
||||
- [ ] Export.php (RIS-Export-Anpassungen)
|
||||
- [ ] BrowseController.php
|
||||
- [ ] CartController.php
|
||||
- [ ] CoverController.php
|
||||
- [ ] FeedbackController.php
|
||||
- [ ] AjaxController.php
|
||||
- [ ] Theme BIBBNeo (Templates, CSS, JS)
|
||||
51
config/module.config.php
Normal file
51
config/module.config.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* BIBBNeo Module Configuration
|
||||
*
|
||||
* This module provides:
|
||||
* - SolrDspace RecordDriver for DSpace records (recordtype = "dspace")
|
||||
* - Extended SolrMarc RecordDriver with BIBB-specific fields
|
||||
* - BIBB citation formats
|
||||
*
|
||||
* @category BIBBNeo
|
||||
* @package Module
|
||||
*/
|
||||
|
||||
namespace BIBBNeo\Module\Configuration;
|
||||
|
||||
$config = [
|
||||
'service_manager' => [
|
||||
'allow_override' => true,
|
||||
],
|
||||
|
||||
'vufind' => [
|
||||
'plugin_managers' => [
|
||||
// Register custom RecordDrivers
|
||||
'recorddriver' => [
|
||||
'factories' => [
|
||||
// DSpace RecordDriver
|
||||
\BIBBNeo\RecordDriver\SolrDspace::class =>
|
||||
\BIBBNeo\RecordDriver\SolrDspaceFactory::class,
|
||||
// Extended BIBB MARC RecordDriver
|
||||
\BIBBNeo\RecordDriver\SolrMarc::class =>
|
||||
\BIBBNeo\RecordDriver\SolrMarcFactory::class,
|
||||
],
|
||||
'aliases' => [
|
||||
// VuFind uses recordtype field to resolve driver:
|
||||
// recordtype "dspace" → SolrDspace driver
|
||||
'SolrDspace' => \BIBBNeo\RecordDriver\SolrDspace::class,
|
||||
// Override default SolrMarc with BIBB version
|
||||
\VuFind\RecordDriver\SolrMarc::class =>
|
||||
\BIBBNeo\RecordDriver\SolrMarc::class,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
// Disable SimilarItemsCarousel (previously done via module.config.php hack)
|
||||
// Note: In VuFind 10.2 this can also be configured via config.ini
|
||||
// [Record] -> tabs setting. Keeping it here for explicitness.
|
||||
],
|
||||
];
|
||||
|
||||
return $config;
|
||||
48
src/BIBBNeo/Module.php
Normal file
48
src/BIBBNeo/Module.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* BIBB Neo Module - Custom VuFind module for BIBB
|
||||
* (Bundesinstitut für Berufsbildung)
|
||||
*
|
||||
* Provides custom RecordDrivers for DSpace and MARC records,
|
||||
* BIBB-specific citation formats, and other customizations.
|
||||
*
|
||||
* @category BIBBNeo
|
||||
* @package Module
|
||||
* @author BIBB
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
|
||||
*/
|
||||
|
||||
namespace BIBBNeo;
|
||||
|
||||
/**
|
||||
* Module definition
|
||||
*/
|
||||
class Module
|
||||
{
|
||||
/**
|
||||
* Get module configuration
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return include __DIR__ . '/../../config/module.config.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get autoloader configuration
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAutoloaderConfig()
|
||||
{
|
||||
return [
|
||||
'Laminas\Loader\StandardAutoloader' => [
|
||||
'namespaces' => [
|
||||
__NAMESPACE__ => __DIR__,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
400
src/BIBBNeo/RecordDriver/BIBBRecordTrait.php
Normal file
400
src/BIBBNeo/RecordDriver/BIBBRecordTrait.php
Normal file
@ -0,0 +1,400 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* BIBBRecordTrait - Shared methods for all BIBB RecordDrivers
|
||||
*
|
||||
* Contains accessor methods for BIBB-specific Solr fields that are
|
||||
* common to both DSpace and MARC records, plus overrides of VuFind
|
||||
* core methods for BIBB-specific behavior.
|
||||
*
|
||||
* @category BIBBNeo
|
||||
* @package RecordDrivers
|
||||
* @author BIBB
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
|
||||
*/
|
||||
|
||||
namespace BIBBNeo\RecordDriver;
|
||||
|
||||
trait BIBBRecordTrait
|
||||
{
|
||||
// ---------------------------------------------------------------
|
||||
// BIBB-specific Solr field accessors
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the citation of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCitations()
|
||||
{
|
||||
return isset($this->fields['citation'])
|
||||
&& is_array($this->fields['citation'])
|
||||
? $this->fields['citation'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the citationdr of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCitationsDrs()
|
||||
{
|
||||
return isset($this->fields['citationdr'])
|
||||
&& is_array($this->fields['citationdr'])
|
||||
? $this->fields['citationdr'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BIBB extend of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getExtend()
|
||||
{
|
||||
return isset($this->fields['extend'])
|
||||
&& is_array($this->fields['extend'])
|
||||
? $this->fields['extend'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BIBB participation of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getParticipations()
|
||||
{
|
||||
return isset($this->fields['participation'])
|
||||
&& is_array($this->fields['participation'])
|
||||
? $this->fields['participation'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BIBB research focus of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getResearchFocus()
|
||||
{
|
||||
return isset($this->fields['researchfocus'])
|
||||
&& is_array($this->fields['researchfocus'])
|
||||
? $this->fields['researchfocus'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the accompanying material of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAccompanyingMaterial()
|
||||
{
|
||||
return isset($this->fields['accompanyingmaterial'])
|
||||
&& is_array($this->fields['accompanyingmaterial'])
|
||||
? $this->fields['accompanyingmaterial'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the additional links of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAdditionalLinks()
|
||||
{
|
||||
return isset($this->fields['additionallinks'])
|
||||
&& is_array($this->fields['additionallinks'])
|
||||
? $this->fields['additionallinks'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dissertation note of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDissertationnote()
|
||||
{
|
||||
return isset($this->fields['dissertationnote'])
|
||||
&& is_array($this->fields['dissertationnote'])
|
||||
? $this->fields['dissertationnote'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original version of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOriginalVersion()
|
||||
{
|
||||
return isset($this->fields['originalversion'])
|
||||
&& is_array($this->fields['originalversion'])
|
||||
? $this->fields['originalversion'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the review-of reference for the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getReviewOf()
|
||||
{
|
||||
return isset($this->fields['reviewof'])
|
||||
? $this->fields['reviewof'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the replaces field.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getReplaces()
|
||||
{
|
||||
return isset($this->fields['replaces'])
|
||||
? $this->fields['replaces'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the isReplacedBy field.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIsReplacedBy()
|
||||
{
|
||||
return isset($this->fields['isreplacedby'])
|
||||
? $this->fields['isreplacedby'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of all Classification entries.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getClassifications()
|
||||
{
|
||||
return isset($this->fields['classification'])
|
||||
&& is_array($this->fields['classification'])
|
||||
? $this->fields['classification'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get inventories for the record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getInventories()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get inventory gaps for the record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getInventoryGaps()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the control number.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCtrlNum()
|
||||
{
|
||||
return !empty($this->fields['ctrlnum'])
|
||||
? $this->fields['ctrlnum'][0]
|
||||
: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the VOE-VZ link(s).
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getVoeVzLink()
|
||||
{
|
||||
return isset($this->fields['voevzlink'])
|
||||
? $this->fields['voevzlink'] : [];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Overridden core methods with BIBB-specific behavior
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get all subject headings - BIBB uses only 'topic', not
|
||||
* geographic, genre, or era.
|
||||
*
|
||||
* @param bool $extended Whether to return a keyed array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAllSubjectHeadings($extended = false)
|
||||
{
|
||||
$headings = [];
|
||||
// BIBB: only use 'topic' field
|
||||
foreach (['topic'] as $field) {
|
||||
if (isset($this->fields[$field])) {
|
||||
$headings = array_merge($headings, $this->fields[$field]);
|
||||
}
|
||||
}
|
||||
|
||||
$callback = function ($i) use ($extended) {
|
||||
return $extended
|
||||
? ['heading' => [$i], 'type' => '', 'source' => '']
|
||||
: [$i];
|
||||
};
|
||||
return array_map($callback, array_unique($headings));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get formats - BIBB prioritizes 'medium' field over 'format'.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFormats()
|
||||
{
|
||||
if (isset($this->fields['medium'])) {
|
||||
return $this->fields['medium'];
|
||||
}
|
||||
return isset($this->fields['format'])
|
||||
? $this->fields['format'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get general notes - BIBB uses 'additionalremarks' field.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getGeneralNotes()
|
||||
{
|
||||
return isset($this->fields['additionalremarks'])
|
||||
? $this->fields['additionalremarks'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get series - BIBB combines series and series2.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSeries()
|
||||
{
|
||||
$fields = [];
|
||||
if (isset($this->fields['series']) && !empty($this->fields['series'])) {
|
||||
$val = $this->fields['series'];
|
||||
if (is_array($val)) {
|
||||
foreach ($val as $s) {
|
||||
$fields[] = ['name' => $s, 'number' => ''];
|
||||
}
|
||||
} else {
|
||||
$fields[] = ['name' => $val, 'number' => ''];
|
||||
}
|
||||
}
|
||||
if (isset($this->fields['series2']) && !empty($this->fields['series2'])) {
|
||||
$val = $this->fields['series2'];
|
||||
if (is_array($val)) {
|
||||
foreach ($val as $s) {
|
||||
$fields[] = ['name' => $s, 'number' => ''];
|
||||
}
|
||||
} else {
|
||||
$fields[] = ['name' => $val, 'number' => ''];
|
||||
}
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first part of the title (before colon).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMainTitle()
|
||||
{
|
||||
$t = '';
|
||||
if (isset($this->fields['title'])) {
|
||||
if (strpos($this->fields['title'], ':') !== false) {
|
||||
$t = trim(strstr($this->fields['title'], ':', true));
|
||||
} else {
|
||||
$t = $this->fields['title'];
|
||||
}
|
||||
}
|
||||
return $t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get container volume - handles array values with "und" separator.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContainerVolume()
|
||||
{
|
||||
$ret = '';
|
||||
if (isset($this->fields['container_volume'])) {
|
||||
if (is_array($this->fields['container_volume'])) {
|
||||
$ret = implode(' und ', $this->fields['container_volume']);
|
||||
} else {
|
||||
$ret = $this->fields['container_volume'];
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the review status / contents of the title.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContents()
|
||||
{
|
||||
return isset($this->fields['contents'])
|
||||
? $this->fields['contents'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the alternative title of the record.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAlternativeTitle()
|
||||
{
|
||||
return isset($this->fields['title_alt'])
|
||||
? $this->fields['title_alt'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the collection(s) for the record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCollection()
|
||||
{
|
||||
if (isset($this->fields['collection'])
|
||||
&& !empty($this->fields['collection'])
|
||||
) {
|
||||
return is_array($this->fields['collection'])
|
||||
? $this->fields['collection']
|
||||
: [$this->fields['collection']];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get supported citation formats - BIBB custom formats.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getSupportedCitationFormats()
|
||||
{
|
||||
return ['BIBB', 'BIBBBWP', 'APA'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get TOC - disabled for BIBB.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTOC()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
439
src/BIBBNeo/RecordDriver/SolrDspace.php
Normal file
439
src/BIBBNeo/RecordDriver/SolrDspace.php
Normal file
@ -0,0 +1,439 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* RecordDriver for DSpace records in the BIBB Solr index.
|
||||
*
|
||||
* Activated automatically when Solr field recordtype = "dspace".
|
||||
* Extends the core SolrDefault driver and adds DSpace-specific
|
||||
* methods for bitstreams, handles, rights/embargo, and URL handling.
|
||||
*
|
||||
* @category BIBBNeo
|
||||
* @package RecordDrivers
|
||||
* @author BIBB
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
|
||||
*/
|
||||
|
||||
namespace BIBBNeo\RecordDriver;
|
||||
|
||||
class SolrDspace extends \VuFind\RecordDriver\SolrDefault
|
||||
{
|
||||
use BIBBRecordTrait;
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// DSpace-specific field accessors
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the filetype of the bitstream.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFileType()
|
||||
{
|
||||
return isset($this->fields['filetype'])
|
||||
&& is_array($this->fields['filetype'])
|
||||
? $this->fields['filetype'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the license of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLicense()
|
||||
{
|
||||
return isset($this->fields['license'])
|
||||
&& is_array($this->fields['license'])
|
||||
? $this->fields['license'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rights license of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRightsLicense()
|
||||
{
|
||||
return isset($this->fields['rightslicense'])
|
||||
&& is_array($this->fields['rightslicense'])
|
||||
? $this->fields['rightslicense'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rights URI of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRightsUri()
|
||||
{
|
||||
return isset($this->fields['rightsuri'])
|
||||
&& is_array($this->fields['rightsuri'])
|
||||
? $this->fields['rightsuri'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rights holder of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRightsHolder()
|
||||
{
|
||||
return isset($this->fields['rightsholder'])
|
||||
&& is_array($this->fields['rightsholder'])
|
||||
? $this->fields['rightsholder'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the embargo terms of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getEmbargoTerms()
|
||||
{
|
||||
return isset($this->fields['embargoterms'])
|
||||
&& is_array($this->fields['embargoterms'])
|
||||
? $this->fields['embargoterms'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the embargo lift date of the current record.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getEmbargoLiftDate()
|
||||
{
|
||||
return isset($this->fields['embargoliftdate'])
|
||||
&& is_array($this->fields['embargoliftdate'])
|
||||
? $this->fields['embargoliftdate'] : [];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// DSpace-specific URL handling
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Base URL for BIBB DSpace instance.
|
||||
*/
|
||||
protected const DSPACE_BASE_URL = 'https://bibb-dspace.bibb.de';
|
||||
|
||||
/**
|
||||
* Check if a URL is a DSpace handle URL that should be filtered out.
|
||||
*
|
||||
* @param string $url URL to check
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isDspaceHandleUrl($url)
|
||||
{
|
||||
$patterns = [
|
||||
self::DSPACE_BASE_URL . '/handle/BIBB',
|
||||
self::DSPACE_BASE_URL . '/jspui/handle/BIBB',
|
||||
];
|
||||
foreach ($patterns as $pattern) {
|
||||
if (strncmp($url, $pattern, strlen($pattern)) === 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a URL is a DSpace bitstream REST URL.
|
||||
*
|
||||
* @param string $url URL to check
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isDspaceBitstreamUrl($url)
|
||||
{
|
||||
return strncmp(
|
||||
$url,
|
||||
self::DSPACE_BASE_URL . '/rest/bitstreams',
|
||||
strlen(self::DSPACE_BASE_URL . '/rest/bitstreams')
|
||||
) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a URL string to extract description and URL parts.
|
||||
*
|
||||
* Handles patterns like:
|
||||
* "http://example.com (Description)"
|
||||
* "http://example.com [Description]"
|
||||
*
|
||||
* @param string $pid Raw URL/PID string
|
||||
*
|
||||
* @return array with keys 'url' and 'desc'
|
||||
*/
|
||||
protected function parseUrlDescription($pid)
|
||||
{
|
||||
$url = $pid;
|
||||
$desc = '';
|
||||
|
||||
// Check for description in parentheses
|
||||
if (($start = strrpos($pid, '(')) !== false) {
|
||||
$end = strrpos($pid, ')');
|
||||
if ($end !== false) {
|
||||
$desc = substr($pid, $start + 1, $end - $start - 1);
|
||||
$url = trim(substr($pid, 0, $start));
|
||||
$url = str_replace('(Volltext)', '', $url);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for description in brackets
|
||||
if (($start = strrpos($pid, '[')) !== false) {
|
||||
$end = strrpos($pid, ']');
|
||||
if ($end !== false) {
|
||||
$desc = substr($pid, $start + 1, $end - $start - 1);
|
||||
$url = trim(substr($pid, 0, $start));
|
||||
}
|
||||
}
|
||||
|
||||
// Fix bare www. URLs
|
||||
if (strncmp($url, 'www.bibb.de', strlen('www.bibb.de')) === 0) {
|
||||
$url = 'https://' . $url;
|
||||
}
|
||||
|
||||
if (strlen($url) === 0) {
|
||||
$url = $pid;
|
||||
}
|
||||
|
||||
$url = trim(str_replace('(Volltext)', '', $url));
|
||||
|
||||
return ['url' => $url, 'desc' => $desc];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a URN to a URL.
|
||||
*
|
||||
* @param string $urn URN string
|
||||
*
|
||||
* @return array Link array with desc, displaytext, url
|
||||
*/
|
||||
protected function resolveUrn($urn)
|
||||
{
|
||||
return [
|
||||
'desc' => 'Volltext über anderen Anbieter (ggf. kostenpflichtig)',
|
||||
'displaytext' => $urn,
|
||||
'url' => 'https://nbn-resolving.org/' . urlencode($urn),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a DOI to a URL.
|
||||
*
|
||||
* @param string $pid Raw DOI string (with prefix)
|
||||
*
|
||||
* @return array Link array with desc, displaytext, url
|
||||
*/
|
||||
protected function resolveDoi($pid)
|
||||
{
|
||||
$lower = strtolower($pid);
|
||||
$start = 0;
|
||||
if (strncmp($lower, 'doi:', 4) === 0) {
|
||||
$start = 4;
|
||||
} elseif (strncmp($lower, 'http://dx.doi.org/', 18) === 0) {
|
||||
$start = 18;
|
||||
}
|
||||
|
||||
return [
|
||||
'desc' => 'Volltext über anderen Anbieter (ggf. kostenpflichtig)',
|
||||
'displaytext' => $pid,
|
||||
'url' => 'https://doi.org/' . urlencode(trim(substr($pid, $start, 100))),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string is a DOI.
|
||||
*
|
||||
* @param string $pid URL/PID string
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isDoi($pid)
|
||||
{
|
||||
$lower = strtolower($pid);
|
||||
return strncmp($lower, 'doi:', 4) === 0
|
||||
|| strncmp($lower, 'http://dx.doi.org/', 18) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string is a URN.
|
||||
*
|
||||
* @param string $pid URL/PID string
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isUrn($pid)
|
||||
{
|
||||
return strncmp($pid, 'urn:nbn:de:', 11) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get online links with full URL resolution and description parsing.
|
||||
*
|
||||
* This is the main method for building display links for DSpace records.
|
||||
* It handles DSpace bitstreams, DOIs, URNs, VOE-VZ links, and
|
||||
* generic URLs with label extraction.
|
||||
*
|
||||
* @param bool $expand If true, fall back to PID-based links when no
|
||||
* direct links are found
|
||||
*
|
||||
* @return array Array of associative arrays with keys:
|
||||
* desc, displaytext, url
|
||||
*/
|
||||
public function getOnlineLinks($expand = false)
|
||||
{
|
||||
if (!isset($this->fields['url'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$retPids = [];
|
||||
$ret = [];
|
||||
$voevzlink = $this->getVoeVzLink();
|
||||
$bitstreamIndex = 0;
|
||||
|
||||
foreach ($this->fields['url'] as $pid) {
|
||||
// Skip DSpace handle URLs (these are internal)
|
||||
if ($this->isDspaceHandleUrl($pid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle URNs
|
||||
if ($this->isUrn($pid)) {
|
||||
$retPids[] = $this->resolveUrn($pid);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle DOIs
|
||||
if ($this->isDoi($pid)) {
|
||||
$retPids[] = $this->resolveDoi($pid);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle DSpace bitstream REST URLs
|
||||
$url = '';
|
||||
$desc = '';
|
||||
|
||||
if ($this->isDspaceBitstreamUrl($pid)) {
|
||||
// Use VOE-VZ link if available, otherwise use bitstream URL
|
||||
$url = isset($voevzlink[$bitstreamIndex])
|
||||
? $voevzlink[$bitstreamIndex]
|
||||
: $pid;
|
||||
$bitstreamIndex++;
|
||||
|
||||
$desc = 'Volltext';
|
||||
// Extract description from parentheses if present
|
||||
if (($start = strrpos($pid, '(')) !== false) {
|
||||
$end = strrpos($pid, ')');
|
||||
if ($end !== false) {
|
||||
$desc = substr($pid, $start + 1, $end - $start - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse description from URL string (parentheses/brackets)
|
||||
$parsed = $this->parseUrlDescription($pid);
|
||||
if (!empty($parsed['desc'])) {
|
||||
$desc = $parsed['desc'];
|
||||
}
|
||||
if (empty($url)) {
|
||||
$url = $parsed['url'];
|
||||
}
|
||||
|
||||
$ret[] = [
|
||||
'desc' => $desc,
|
||||
'displaytext' => $pid,
|
||||
'url' => $url,
|
||||
];
|
||||
}
|
||||
|
||||
if (!$expand) {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// In expand mode: fall back to PID-based links if no direct links found
|
||||
return count($ret) === 0 ? $retPids : $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get persistent identifiers (DOIs, URNs) excluding DSpace handles.
|
||||
*
|
||||
* @return array Array of associative arrays with displaytext and link keys
|
||||
*/
|
||||
public function getPids()
|
||||
{
|
||||
if (!isset($this->fields['url'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$ret = [];
|
||||
foreach ($this->fields['url'] as $pid) {
|
||||
// Skip DSpace handle URLs
|
||||
if ($this->isDspaceHandleUrl($pid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Collect URNs
|
||||
if ($this->isUrn($pid)) {
|
||||
$ret[] = [
|
||||
'displaytext' => $pid,
|
||||
'link' => 'https://nbn-resolving.org/' . urlencode($pid),
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Collect DOIs
|
||||
if ($this->isDoi($pid)) {
|
||||
$resolved = $this->resolveDoi($pid);
|
||||
$ret[] = [
|
||||
'displaytext' => $pid,
|
||||
'link' => $resolved['url'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get formats, filtered to remove "Electronic resource" when only
|
||||
* DSpace links are present (no external electronic links).
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFormatsFiltered()
|
||||
{
|
||||
$formats = $this->getFormats();
|
||||
$hasElectronic = in_array('Electronic resource', $formats);
|
||||
|
||||
if (!$hasElectronic) {
|
||||
return $formats;
|
||||
}
|
||||
|
||||
// Remove "Electronic resource" from format list
|
||||
$filtered = array_filter($formats, function ($f) {
|
||||
return $f !== 'Electronic resource';
|
||||
});
|
||||
|
||||
// Check if there are non-DSpace URLs that justify "Electronic resource"
|
||||
$urls = isset($this->fields['url']) && is_array($this->fields['url'])
|
||||
? $this->fields['url'] : [];
|
||||
|
||||
$hasExternalUrls = false;
|
||||
foreach ($urls as $url) {
|
||||
if (!$this->isDspaceHandleUrl($url)
|
||||
&& strncmp($url, self::DSPACE_BASE_URL, strlen(self::DSPACE_BASE_URL)) !== 0
|
||||
) {
|
||||
$hasExternalUrls = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Only re-add "Electronic resource" if there are external URLs
|
||||
if ($hasExternalUrls) {
|
||||
$filtered[] = 'Electronic resource';
|
||||
}
|
||||
|
||||
return array_values($filtered);
|
||||
}
|
||||
}
|
||||
40
src/BIBBNeo/RecordDriver/SolrDspaceFactory.php
Normal file
40
src/BIBBNeo/RecordDriver/SolrDspaceFactory.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Factory for SolrDspace RecordDriver.
|
||||
*
|
||||
* @category BIBBNeo
|
||||
* @package RecordDrivers
|
||||
* @author BIBB
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
|
||||
*/
|
||||
|
||||
namespace BIBBNeo\RecordDriver;
|
||||
|
||||
use Laminas\ServiceManager\Exception\ServiceNotCreatedException;
|
||||
use Laminas\ServiceManager\Exception\ServiceNotFoundException;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class SolrDspaceFactory extends \VuFind\RecordDriver\SolrDefaultFactory
|
||||
{
|
||||
/**
|
||||
* Create an object (VuFind 10.2 pattern)
|
||||
*
|
||||
* @param ContainerInterface $container Service manager
|
||||
* @param string $requestedName Service being created
|
||||
* @param null|array $options Extra options (optional)
|
||||
*
|
||||
* @return SolrDspace
|
||||
*
|
||||
* @throws ServiceNotFoundException if unable to resolve the service.
|
||||
* @throws ServiceNotCreatedException if an exception is raised when creating.
|
||||
*/
|
||||
public function __invoke(
|
||||
ContainerInterface $container,
|
||||
$requestedName,
|
||||
array $options = null
|
||||
) {
|
||||
$driver = parent::__invoke($container, $requestedName, $options);
|
||||
return $driver;
|
||||
}
|
||||
}
|
||||
25
src/BIBBNeo/RecordDriver/SolrMarc.php
Normal file
25
src/BIBBNeo/RecordDriver/SolrMarc.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Extended SolrMarc RecordDriver for BIBB MARC records (from Koha).
|
||||
*
|
||||
* Overrides the core SolrMarc driver to add BIBB-specific fields
|
||||
* and behavior via the BIBBRecordTrait.
|
||||
*
|
||||
* @category BIBBNeo
|
||||
* @package RecordDrivers
|
||||
* @author BIBB
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
|
||||
*/
|
||||
|
||||
namespace BIBBNeo\RecordDriver;
|
||||
|
||||
class SolrMarc extends \VuFind\RecordDriver\SolrMarc
|
||||
{
|
||||
use BIBBRecordTrait;
|
||||
|
||||
// The trait provides all BIBB-specific methods.
|
||||
// MARC-specific overrides can be added here as needed.
|
||||
// For example, methods that need access to raw MARC data
|
||||
// via $this->getMarcReader() belong here, not in the trait.
|
||||
}
|
||||
40
src/BIBBNeo/RecordDriver/SolrMarcFactory.php
Normal file
40
src/BIBBNeo/RecordDriver/SolrMarcFactory.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Factory for BIBB SolrMarc RecordDriver.
|
||||
*
|
||||
* @category BIBBNeo
|
||||
* @package RecordDrivers
|
||||
* @author BIBB
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
|
||||
*/
|
||||
|
||||
namespace BIBBNeo\RecordDriver;
|
||||
|
||||
use Laminas\ServiceManager\Exception\ServiceNotCreatedException;
|
||||
use Laminas\ServiceManager\Exception\ServiceNotFoundException;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
class SolrMarcFactory extends \VuFind\RecordDriver\SolrDefaultFactory
|
||||
{
|
||||
/**
|
||||
* Create an object (VuFind 10.2 pattern)
|
||||
*
|
||||
* @param ContainerInterface $container Service manager
|
||||
* @param string $requestedName Service being created
|
||||
* @param null|array $options Extra options (optional)
|
||||
*
|
||||
* @return SolrMarc
|
||||
*
|
||||
* @throws ServiceNotFoundException if unable to resolve the service.
|
||||
* @throws ServiceNotCreatedException if an exception is raised when creating.
|
||||
*/
|
||||
public function __invoke(
|
||||
ContainerInterface $container,
|
||||
$requestedName,
|
||||
array $options = null
|
||||
) {
|
||||
$driver = parent::__invoke($container, $requestedName, $options);
|
||||
return $driver;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user