Bug 11175: Show record component parts in the detail view

Shows the component records of a host, on the hosts detail view in
staff client or OPAC, with clickable links to the component records.

The host does not require linking entries to the components, but
components do require a link to the host record via 773$w.

Adds a new search index, Control-number-identifier (aka cni), which
indexes the 003 controlfield.

Adds 'Yet Another System Preference', ShowComponentRecords, which can
be used to turn this feature on or off in staff client and/or OPAC,
and defaults to off.

When looking up the component part records, the code searches for
records with (773$w=Host001 and 003=Host003) or 773$w='Host003 Host001'
or, if the 003 is not defined in the Host, 773$w=Host001.

Does not use easyanalytics or useControlNumber.

Only for MARC21 biblios - UNIMARC has not been updated.

staff-global.css and opac.css have not been recreated, so you need
to use sass to recreate those from staff-global.scss and opac.scss

Test plan:

0) Apply patch
1) perl bulkmarcimport -file /tmp/easypiano.mrc -m MARCXML
   (This file is an attachment on the bug)
2) rebuild the zebra biblio index
3) Search for "easy piano" in staff client, and go to
   the biblio detail page. You should not see anything different
   in the record detail page.
4) Do the same on OPAC.
5) Change the ShowComponentRecords syspref appropriately and check
   the record detail page in staff client and OPAC.
   You should see a list of component part records.

Rebased-by: Joonas Kylmälä <joonas.kylmala@helsinki.fi>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pasi Kallinen <pasi.kallinen@koha-suomi.fi>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Andrew Nugged <nugged@gmail.com>

JD amended path
-    if ($xslsyspref =~ m/Details/) {
+    if ( $xslsyspref eq "OPACXSLTDetailsDisplay" || $xslsyspref eq "XSLTDetailsDisplay" ) {

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
This commit is contained in:
Pasi Kallinen 2018-08-20 09:51:55 +03:00 committed by Jonathan Druart
parent 54a1c5433b
commit 60505e57d6
11 changed files with 235 additions and 1 deletions

View file

@ -285,8 +285,29 @@ sub XSLTParse4Display {
}
$varxml .= "</variables>\n";
my $partsxml = '';
# possibly insert component records into Detail views
if ( $xslsyspref eq "OPACXSLTDetailsDisplay" || $xslsyspref eq "XSLTDetailsDisplay" ) {
my $showcomp = C4::Context->preference('ShowComponentRecords');
if ( $showcomp eq 'both' ||
($showcomp eq 'staff' && $xslsyspref !~ m/OPAC/ ) ||
($showcomp eq 'opac' && $xslsyspref =~ m/OPAC/ ) ) {
my $biblio = Koha::Biblios->find( $biblionumber );
if ( $biblio->components() ) {
my @componentPartRecordXML = ('<componentPartRecords>');
for my $cb ( @{ $biblio->components() } ) {
# Remove the xml header
$cb =~ s/^<\?xml.*?\?>//;
push @componentPartRecordXML, decode('utf8', $cb);
}
push @componentPartRecordXML, '</componentPartRecords>';
$partsxml = join "\n", @componentPartRecordXML;
}
}
}
my $sysxml = get_xslt_sysprefs();
$xmlrecord =~ s/\<\/record\>/$itemsxml$sysxml$varxml\<\/record\>/;
$xmlrecord =~ s/\<\/record\>/$itemsxml$sysxml$varxml$partsxml\<\/record\>/;
if ($fixamps) { # We need to correct the ampersand entities that Zebra outputs
$xmlrecord =~ s/\&amp;amp;/\&amp;/g;
$xmlrecord =~ s/\&amp\;lt\;/\&lt\;/g;

View file

@ -41,6 +41,8 @@ use Koha::Items;
use Koha::Libraries;
use Koha::Suggestions;
use Koha::Subscriptions;
use Koha::SearchEngine;
use Koha::SearchEngine::Search;
=head1 NAME
@ -476,6 +478,49 @@ sub suggestions {
return Koha::Suggestions->_new_from_dbic( $suggestions_rs );
}
=head3 components
my $components = $self->components();
Returns an array of MARCXML data, which are component parts of
this object (MARC21 773$w points to this)
=cut
sub components {
my ($self) = @_;
return undef if (C4::Context->preference('marcflavour') ne 'MARC21');
if (!defined($self->{_components})) {
my $marc = C4::Biblio::GetMarcBiblio({ biblionumber => $self->id });
my $pf001 = $marc->field('001') || undef;
my $searcher = Koha::SearchEngine::Search->new({index => $Koha::SearchEngine::BIBLIOS_INDEX});
if (defined($pf001)) {
my $pf003 = $marc->field('003') || undef;
my $searchstr;
if (!defined($pf003)) {
# search for 773$w='Host001'
$searchstr = "rcn='".$pf001->data()."'";
} else {
# search for (773$w='Host001' and 003='Host003') or 773$w='Host003 Host001')
$searchstr = "(rcn='".$pf001->data()."' and cni='".$pf003->data()."')";
$searchstr .= " or rcn='".$pf003->data()." ".$pf001->data()."'";
}
my ( $errors, $results, $total_hits ) = $searcher->simple_search_compat( $searchstr, 0, undef );
$self->{_components} = $results if ( defined($results) && scalar(@$results) );
} else {
warn "Record $self->id has no 001";
}
}
return $self->{_components};
}
=head3 subscriptions
my $subscriptions = $self->subscriptions

View file

@ -0,0 +1,6 @@
$DBversion = 'XXX'; # will be replaced by the RM
if( CheckVersion( $DBversion ) ) {
$dbh->do("INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES ('ShowComponentRecords', 'nowhere', 'nowhere|staff|opac|both','In which record detail pages to show list of the component records, as linked via 773','Choice')");
SetVersion( $DBversion );
print "Upgrade to $DBversion done (Bug 11175: Show component records in detail views)\n";
}

View file

@ -615,6 +615,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `
('ShelfBrowserUsesHomeBranch','1','1','Use the item home branch when finding items for the shelf browser.','YesNo'),
('ShelfBrowserUsesLocation','1','1','Use the item location when finding items for the shelf browser.','YesNo'),
('ShowAllCheckins', '0', '', 'Show all checkins', 'YesNo'),
('ShowComponentRecords', 'nowhere', 'nowhere|staff|opac|both','In which record detail pages to show list of the component records, as linked via 773','Choice'),
('showLastPatron','0','','If ON, enables the last patron feature in the intranet','YesNo'),
('ShowPatronImageInWebBasedSelfCheck','0','','If ON, displays patron image when a patron uses web-based self-checkout','YesNo'),
('ShowReviewer','full','none|full|first|surname|firstandinitial|username','Choose how a commenter\'s identity is presented alongside comments in the OPAC','Choice'),

View file

@ -614,6 +614,14 @@ ol {
padding: 7px 0;
}
.componentPartRecordsContainer {
float: right;
overflow-y: auto;
overflow-x: hidden;
max-width: 50%;
max-height: 25em;
}
#editions {
table,
td {

View file

@ -181,6 +181,15 @@ Staff interface:
1: Show
0: "Don't show"
- a search field pulldown for 'Search the catalog' boxes.
-
- Show a list of component records, as linked via field 773, in
- pref: ShowComponentRecords
choices:
nowhere: "no"
staff: "staff client"
opac: "OPAC"
both: "both staff client and OPAC"
- record detail pages.
Authentication:
-
- pref: staffShibOnly

View file

@ -115,6 +115,8 @@
</h1>
</xsl:if>
<xsl:call-template name="showComponentParts"/>
<!--Bug 13381 -->
<xsl:if test="marc:datafield[@tag=245]">
<h1 class="title" property="name">

View file

@ -578,6 +578,72 @@
</xsl:if>
</xsl:template>
<xsl:template name="showComponentParts">
<!-- Component part records: Displaying title and author of component part records -->
<xsl:if test="marc:componentPartRecords">
<div class="results_summary componentPartRecordsContainer">
<h5>Component part records</h5>
<ol class="componentParts">
<xsl:for-each select="marc:componentPartRecords/marc:record">
<li>
<span class="componentPartRecord">
<span class="componentPartRecordTitle">
<a>
<xsl:attribute name="href">/cgi-bin/koha/catalogue/detail.pl?biblionumber=<xsl:value-of select="marc:datafield[@tag=999]/marc:subfield[@code='c']" /></xsl:attribute>
<xsl:choose>
<xsl:when test="marc:datafield[@tag=245]/marc:subfield[@code='a']">
<xsl:value-of select="substring-before( concat(marc:datafield[@tag=245]/marc:subfield[@code='a'], '/'), '/')" />
</xsl:when>
<xsl:when test="marc:datafield[@tag=240]/marc:subfield[@code='a']">
<xsl:for-each select="marc:datafield[@tag=240]">
<xsl:call-template name="chopPunctuation">
<xsl:with-param name="chopString">
<xsl:call-template name="subfieldSelect">
<xsl:with-param name="codes">amnp</xsl:with-param>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:when test="marc:datafield[@tag=130]/marc:subfield[@code='a']">
<xsl:for-each select="marc:datafield[@tag=130]">
<xsl:call-template name="chopPunctuation">
<xsl:with-param name="chopString">
<xsl:call-template name="subfieldSelect">
<xsl:with-param name="codes">amnp</xsl:with-param>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:text>[Record with no title statement]</xsl:text>
</xsl:otherwise>
</xsl:choose>
</a>
</span>
<xsl:choose>
<xsl:when test="marc:datafield[@tag=100]/marc:subfield[@code='a']">
-
<span class="componentPartRecordAuthor">
<xsl:value-of select="marc:datafield[@tag=100]/marc:subfield[@code='a']" />
</span>
</xsl:when>
<xsl:when test="marc:datafield[@tag=110]/marc:subfield[@code='a']">
-
<span class="componentPartRecordAuthor">
<xsl:value-of select="marc:datafield[@tag=110]/marc:subfield[@code='a']" />
</span>
</xsl:when>
</xsl:choose>
</span>
</li>
</xsl:for-each>
</ol>
</div>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
<!-- Stylus Studio meta-information - (c)1998-2002 eXcelon Corp.

View file

@ -292,6 +292,14 @@ th {
}
.componentPartRecordsContainer {
float: right;
overflow-y: auto;
overflow-x: hidden;
max-width: 50%;
max-height: 25em;
}
#members {
p {
color: #727272;

View file

@ -127,6 +127,8 @@
</h2>
</xsl:if>
<xsl:call-template name="showComponentParts"/>
<!--Bug 13381 -->
<xsl:if test="marc:datafield[@tag=245]">
<h1 class="title" property="name">

View file

@ -542,6 +542,72 @@
</xsl:if>
</xsl:template>
<xsl:template name="showComponentParts">
<!-- Component part records: Displaying title and author of component part records -->
<xsl:if test="marc:componentPartRecords">
<div class="results_summary componentPartRecordsContainer">
<h5>Component part records</h5>
<ol class="componentParts">
<xsl:for-each select="marc:componentPartRecords/marc:record">
<li>
<span class="componentPartRecord">
<span class="componentPartRecordTitle">
<a>
<xsl:attribute name="href">/cgi-bin/koha/opac-detail.pl?biblionumber=<xsl:value-of select="marc:datafield[@tag=999]/marc:subfield[@code='c']" /></xsl:attribute>
<xsl:choose>
<xsl:when test="marc:datafield[@tag=245]/marc:subfield[@code='a']">
<xsl:value-of select="substring-before( concat(marc:datafield[@tag=245]/marc:subfield[@code='a'], '/'), '/')" />
</xsl:when>
<xsl:when test="marc:datafield[@tag=240]/marc:subfield[@code='a']">
<xsl:for-each select="marc:datafield[@tag=240]">
<xsl:call-template name="chopPunctuation">
<xsl:with-param name="chopString">
<xsl:call-template name="subfieldSelect">
<xsl:with-param name="codes">amnp</xsl:with-param>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:when test="marc:datafield[@tag=130]/marc:subfield[@code='a']">
<xsl:for-each select="marc:datafield[@tag=130]">
<xsl:call-template name="chopPunctuation">
<xsl:with-param name="chopString">
<xsl:call-template name="subfieldSelect">
<xsl:with-param name="codes">amnp</xsl:with-param>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:text>[Record with no title statement]</xsl:text>
</xsl:otherwise>
</xsl:choose>
</a>
</span>
<xsl:choose>
<xsl:when test="marc:datafield[@tag=100]/marc:subfield[@code='a']">
-
<span class="componentPartRecordAuthor">
<xsl:value-of select="marc:datafield[@tag=100]/marc:subfield[@code='a']" />
</span>
</xsl:when>
<xsl:when test="marc:datafield[@tag=110]/marc:subfield[@code='a']">
-
<span class="componentPartRecordAuthor">
<xsl:value-of select="marc:datafield[@tag=110]/marc:subfield[@code='a']" />
</span>
</xsl:when>
</xsl:choose>
</span>
</li>
</xsl:for-each>
</ol>
</div>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
<!-- Stylus Studio meta-information - (c)1998-2002 eXcelon Corp.