From 7aef071a2c16dc702885e61f85360bb80b1591c8 Mon Sep 17 00:00:00 2001 From: Olli-Antti Kivilahti Date: Mon, 27 Jan 2014 15:58:32 +0200 Subject: [PATCH] Bug 11175 - Show the parent record's component parts in the detailed views. Business layer. TERMINOLOGY: "Component part": A Bibliographic record connected to it's host record via $773w -> 001 or via other Record-control-number-index relation. "Host record": A bibliographic record which contains child records. Host record doesn't need to have a link to the child record. USEFUL: For music cataloguers whose jobs depend on these. For browsing the contents of a musical record. Provides the basis for a high quality music library service. Because Koha has the building blocks to create these component part records out of box, it is odd that they can't be displayed out of box. This patch adds a system preference AddComponentPartRecordsToDetailedViews. This controls if component part records data is appended after the bibliographic data for XSLT parsing. Also makes sure that component part records are not pulled needlessly for non-detailed views as this would cripple performance. --- C4/XSLT.pm | 67 +++++++++++++++++++++- installer/data/mysql/sysprefs.sql | 1 + installer/data/mysql/updatedatabase.pl | 8 +++ .../en/modules/admin/preferences/cataloguing.pref | 8 +++ 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/C4/XSLT.pm b/C4/XSLT.pm index d85b048..324e6ba 100644 --- a/C4/XSLT.pm +++ b/C4/XSLT.pm @@ -158,6 +158,9 @@ sub _get_best_default_xslt_filename { sub XSLTParse4Display { my ( $biblionumber, $orig_record, $xslsyspref, $fixamps, $hidden_items ) = @_; + + my $shouldIPullInComponentPartRecords; #We don't want to pull component part records if they are not needed! Show component part records only for detailed views. + my $xslfilename = C4::Context->preference($xslsyspref); if ( $xslfilename =~ /^\s*"?default"?\s*$/i ) { my $htdocs; @@ -169,6 +172,7 @@ sub XSLTParse4Display { $theme = C4::Context->preference("template"); $xslfile = C4::Context->preference('marcflavour') . "slim2intranetDetail.xsl"; + $shouldIPullInComponentPartRecords = 1; } elsif ($xslsyspref eq "XSLTResultsDisplay") { $htdocs = C4::Context->config('intrahtdocs'); $theme = C4::Context->preference("template"); @@ -179,6 +183,7 @@ sub XSLTParse4Display { $theme = C4::Context->preference("opacthemes"); $xslfile = C4::Context->preference('marcflavour') . "slim2OPACDetail.xsl"; + $shouldIPullInComponentPartRecords = 1; } elsif ($xslsyspref eq "OPACXSLTResultsDisplay") { $htdocs = C4::Context->config('opachtdocs'); $theme = C4::Context->preference("opacthemes"); @@ -193,8 +198,16 @@ sub XSLTParse4Display { $xslfilename =~ s/\{langcode\}/$lang/; } + # grab the XML, run it through our stylesheet, push it out to the browser my $record = transformMARCXML4XSLT($biblionumber, $orig_record); + my $f001Data = $record->field('001'); + $f001Data = $f001Data->data() if defined $f001Data; #Not all records have the field 001?? + + my $componentPartRecordsXML = ''; + $componentPartRecordsXML = _prepareComponentPartRecords($f001Data) if $shouldIPullInComponentPartRecords && + C4::Context->preference('AddComponentPartRecordsToDetailedViews');; + #return $record->as_formatted(); my $itemsxml = buildKohaItemsNamespace($biblionumber, $hidden_items); my $xmlrecord = $record->as_xml(C4::Context->preference('marcflavour')); @@ -214,7 +227,7 @@ sub XSLTParse4Display { $sysxml .= "$sp\n"; } $sysxml .= "\n"; - $xmlrecord =~ s/\<\/record\>/$itemsxml$sysxml\<\/record\>/; + $xmlrecord =~ s/\<\/record\>/$itemsxml$sysxml$componentPartRecordsXML\<\/record\>/; if ($fixamps) { # We need to correct the ampersand entities that Zebra outputs $xmlrecord =~ s/\&amp;/\&/g; } @@ -313,6 +326,58 @@ sub buildKohaItemsNamespace { return $xml; } +=head + + Makes a C4::Search::SimpleSearch() to find all records from the index rcn=Record-control-number matching the given + field 001 value. + Strips some key identifiers from those records. + Builds a XML presentation out of those, ready for the XSLT processing. + + $componentPartRecordsXML = &_prepareComponentPartRecords($field001Data); + + In Koha the field 001 is not the same as the biblionumber! + + Returns: a string containing an XML representation of component part records + In XSL: componentPartRecords/componentPart/title + in addition to title, elements can also be subtitle, biblionumber, author, publishercode, publicationyear + eg. componentPartRecords/componentPart/biblionumber + +=cut +sub _prepareComponentPartRecords { + + my $field001Data = shift; + my $componentPartRecordsXML; + my ($error, $componentPartRecordISOs, $resultSetSize) = C4::Search::SimpleSearch("rcn=$field001Data"); + + if ($resultSetSize && !$error) { + + #Collect the XML elements to a array instead of continuously concatenating a string. + # There might be dozens of component part records and in such a case string concatenation is extremely slow. + my @componentPartRecordXML = (''); #@@componentPartRecordXML vs $componentPartRecordsXML is a nice Perl curiosity! + for my $cr ( @{$componentPartRecordISOs} ) { + push @componentPartRecordXML, ' '; + my $marcrecord = MARC::File::USMARC::decode($cr); + my $componentPartBiblio = TransformMarcToKoha(C4::Context->dbh,$marcrecord,q{}); + + push @componentPartRecordXML, " $componentPartBiblio->{'title'}" if $componentPartBiblio->{'title'}; + push @componentPartRecordXML, " $componentPartBiblio->{'subtitle'}" if $componentPartBiblio->{'subtitle'}; + push @componentPartRecordXML, " $componentPartBiblio->{'biblionumber'}" if $componentPartBiblio->{'biblionumber'}; + push @componentPartRecordXML, " $componentPartBiblio->{'author'}" if $componentPartBiblio->{'author'}; + push @componentPartRecordXML, " $componentPartBiblio->{'publishercode'}" if $componentPartBiblio->{'publishercode'}; + push @componentPartRecordXML, " $componentPartBiblio->{'publicationyear'}" if $componentPartBiblio->{'publicationyear'}; + + push @componentPartRecordXML, ' '; + } + push @componentPartRecordXML, ''; + push @componentPartRecordXML, ''; #Just to make the join operation end with a newline + + #Build the real XML string. + $componentPartRecordsXML = join "\n", @componentPartRecordXML; + + return $componentPartRecordsXML; + } + return ''; #Instantiate this string so we don't get undefined errors when concatenating with this. +} 1; diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql index 661910b..6d0e2a5 100644 --- a/installer/data/mysql/sysprefs.sql +++ b/installer/data/mysql/sysprefs.sql @@ -4,6 +4,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('AcquisitionDetails', '1', '', 'Hide/Show acquisition details on the biblio detail page.', 'YesNo'), ('AcqViewBaskets','user','user|branch|all','Define which baskets a user is allowed to view: his own only, any within his branch or all','Choice'), ('AcqWarnOnDuplicateInvoice','0','','Warn librarians when they try to create a duplicate invoice','YesNo'), +('AddComponentPartRecordsToDetailedViews','1',NULL,'Show component part records in the detailed views.','YesNo'), ('AddPatronLists','categorycode','categorycode|category_type','Allow user to choose what list to pick up from when adding patrons','Choice'), ('advancedMARCeditor','0','','If ON, the MARC editor won\'t display field/subfield descriptions','YesNo'), ('AdvancedSearchTypes','itemtypes','itemtypes|ccode','Select which set of fields comprise the Type limit in the advanced search','Choice'), diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 9039766..e9866b1 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -8074,6 +8074,14 @@ if ( CheckVersion($DBversion) ) { SetVersion($DBversion); } +$DBversion = "3.15.00.XXX"; +if (CheckVersion($DBversion)) { + $dbh->do("INSERT INTO systempreferences ( variable, value, options, explanation, type ) VALUES + ('AddComponentPartRecordsToDetailedViews','1',NULL,'Show component part records in the detailed views.','YesNo');"); + print "Upgrade to $DBversion done (Bug 11175: Show the parent record's component parts in the detailed views.)\n"; + SetVersion($DBversion); +} + =head1 FUNCTIONS =head2 TableExists($table) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref index 169aec4..443a45c 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref @@ -161,6 +161,14 @@ Cataloging: class: short - (Leave blank if not used. Define a range like 192.168..) - + - "Requires XSLTDetailsDisplay and/or OPACXSLTDetailsDisplay system preferences to be active. Works on MARC21. " + - pref: AddComponentPartRecordsToDetailedViews + choices: + yes: Show + no: "Don't show" + - "component part records in the detailed views. This might cause a performance penalty for records with lots of component part records." + - "Technical explanation: This enables appending component part records to the bibliographic record data for the XSLT parsing. Component parts need to be indexed in the rcn-index, in which many by default are." + - - pref: SeparateHoldings choices: yes: Separate -- 1.8.1.2