3 # Copyright 2000-2002 Katipo Communications
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA 02111-1307 USA
24 use MARC::File::USMARC;
25 # Force MARC::File::XML to use LibXML SAX Parser
26 #$XML::SAX::ParserPackage = "XML::LibXML::SAX";
31 use C4::Dates qw/format_date/;
32 use C4::Log; # logaction
37 use vars qw($VERSION @ISA @EXPORT);
43 @ISA = qw( Exporter );
57 &GetBiblioItemByBiblioNumber
58 &GetBiblioFromItemNumber
70 &GetAuthorisedValueDesc
74 &GetPublisherNameFromIsbn
89 # To link headings in a bib record
90 # to authority records.
92 &LinkBibHeadingsToAuthorities
96 # those functions are exported but should not be used
97 # they are usefull is few circumstances, so are exported.
98 # but don't use them unless you're a core developer ;-)
105 &TransformHtmlToMarc2
108 &PrepareItemrecordDisplay
115 C4::Biblio - cataloging management functions
119 Biblio.pm contains functions for managing storage and editing of bibliographic data within Koha. Most of the functions in this module are used for cataloging records: adding, editing, or removing biblios, biblioitems, or items. Koha's stores bibliographic information in three places:
123 =item 1. in the biblio,biblioitems,items, etc tables, which are limited to a one-to-one mapping to underlying MARC data
125 =item 2. as raw MARC in the Zebra index and storage engine
127 =item 3. as raw MARC the biblioitems.marc and biblioitems.marcxml
131 In the 3.0 version of Koha, the authoritative record-level information is in biblioitems.marcxml
133 Because the data isn't completely normalized there's a chance for information to get out of sync. The design choice to go with a un-normalized schema was driven by performance and stability concerns. However, if this occur, it can be considered as a bug : The API is (or should be) complete & the only entry point for all biblio/items managements.
137 =item 1. Compared with MySQL, Zebra is slow to update an index for small data changes -- especially for proc-intensive operations like circulation
139 =item 2. Zebra's index has been known to crash and a backup of the data is necessary to rebuild it in such cases
143 Because of this design choice, the process of managing storage and editing is a bit convoluted. Historically, Biblio.pm's grown to an unmanagable size and as a result we have several types of functions currently:
147 =item 1. Add*/Mod*/Del*/ - high-level external functions suitable for being called from external scripts to manage the collection
149 =item 2. _koha_* - low-level internal functions for managing the koha tables
151 =item 3. Marc management function : as the MARC record is stored in biblioitems.marc(xml), some subs dedicated to it's management are in this package. They should be used only internally by Biblio.pm, the only official entry points being AddBiblio, AddItem, ModBiblio, ModItem.
153 =item 4. Zebra functions used to update the Zebra index
155 =item 5. internal helper functions such as char_decode, checkitems, etc. Some of these probably belong in Koha.pm
159 The MARC record (in biblioitems.marcxml) contains the complete marc record, including items. It also contains the biblionumber. That is the reason why it is not stored directly by AddBiblio, with all other fields . To save a biblio, we need to :
163 =item 1. save datas in biblio and biblioitems table, that gives us a biblionumber and a biblioitemnumber
165 =item 2. add the biblionumber and biblioitemnumber into the MARC records
167 =item 3. save the marc record
171 When dealing with items, we must :
175 =item 1. save the item in items table, that gives us an itemnumber
177 =item 2. add the itemnumber to the item MARC field
179 =item 3. overwrite the MARC record (with the added item) into biblioitems.marc(xml)
181 When modifying a biblio or an item, the behaviour is quite similar.
185 =head1 EXPORTED FUNCTIONS
191 ($biblionumber,$biblioitemnumber) = AddBiblio($record,$frameworkcode);
195 Exported function (core API) for adding a new biblio to koha.
197 The first argument is a C<MARC::Record> object containing the
198 bib to add, while the second argument is the desired MARC
201 This function also accepts a third, optional argument: a hashref
202 to additional options. The only defined option is C<defer_marc_save>,
203 which if present and mapped to a true value, causes C<AddBiblio>
204 to omit the call to save the MARC in C<bibilioitems.marc>
205 and C<biblioitems.marcxml> This option is provided B<only>
206 for the use of scripts such as C<bulkmarcimport.pl> that may need
207 to do some manipulation of the MARC record for item parsing before
208 saving it and which cannot afford the performance hit of saving
209 the MARC record twice. Consequently, do not use that option
210 unless you can guarantee that C<ModBiblioMarc> will be called.
216 my $frameworkcode = shift;
217 my $options = @_ ? shift : undef;
218 my $defer_marc_save = 0;
219 if (defined $options and exists $options->{'defer_marc_save'} and $options->{'defer_marc_save'}) {
220 $defer_marc_save = 1;
223 my ($biblionumber,$biblioitemnumber,$error);
224 my $dbh = C4::Context->dbh;
225 # transform the data into koha-table style data
226 my $olddata = TransformMarcToKoha( $dbh, $record, $frameworkcode );
227 ($biblionumber,$error) = _koha_add_biblio( $dbh, $olddata, $frameworkcode );
228 $olddata->{'biblionumber'} = $biblionumber;
229 ($biblioitemnumber,$error) = _koha_add_biblioitem( $dbh, $olddata );
231 _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
233 # update MARC subfield that stores biblioitems.cn_sort
234 _koha_marc_update_biblioitem_cn_sort($record, $olddata, $frameworkcode);
237 $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode ) unless $defer_marc_save;
239 logaction("CATALOGUING", "ADD", $biblionumber, "biblio") if C4::Context->preference("CataloguingLog");
241 return ( $biblionumber, $biblioitemnumber );
248 ModBiblio( $record,$biblionumber,$frameworkcode);
252 Replace an existing bib record identified by C<$biblionumber>
253 with one supplied by the MARC::Record object C<$record>. The embedded
254 item, biblioitem, and biblionumber fields from the previous
255 version of the bib record replace any such fields of those tags that
256 are present in C<$record>. Consequently, ModBiblio() is not
257 to be used to try to modify item records.
259 C<$frameworkcode> specifies the MARC framework to use
260 when storing the modified bib record; among other things,
261 this controls how MARC fields get mapped to display columns
262 in the C<biblio> and C<biblioitems> tables, as well as
263 which fields are used to store embedded item, biblioitem,
264 and biblionumber data for indexing.
269 my ( $record, $biblionumber, $frameworkcode ) = @_;
270 if (C4::Context->preference("CataloguingLog")) {
271 my $newrecord = GetMarcBiblio($biblionumber);
272 logaction("CATALOGUING", "MODIFY", $biblionumber, "BEFORE=>".$newrecord->as_formatted);
275 my $dbh = C4::Context->dbh;
277 $frameworkcode = "" unless $frameworkcode;
279 # get the items before and append them to the biblio before updating the record, atm we just have the biblio
280 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
281 my $oldRecord = GetMarcBiblio( $biblionumber );
283 # delete any item fields from incoming record to avoid
284 # duplication or incorrect data - use AddItem() or ModItem()
286 foreach my $field ($record->field($itemtag)) {
287 $record->delete_field($field);
290 # once all the items fields are removed, copy the old ones, in order to keep synchronize
291 $record->append_fields($oldRecord->field( $itemtag ));
293 # update biblionumber and biblioitemnumber in MARC
294 # FIXME - this is assuming a 1 to 1 relationship between
295 # biblios and biblioitems
296 my $sth = $dbh->prepare("select biblioitemnumber from biblioitems where biblionumber=?");
297 $sth->execute($biblionumber);
298 my ($biblioitemnumber) = $sth->fetchrow;
300 _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
302 # load the koha-table data object
303 my $oldbiblio = TransformMarcToKoha( $dbh, $record, $frameworkcode );
305 # update MARC subfield that stores biblioitems.cn_sort
306 _koha_marc_update_biblioitem_cn_sort($record, $oldbiblio, $frameworkcode);
308 # update the MARC record (that now contains biblio and items) with the new record data
309 &ModBiblioMarc( $record, $biblionumber, $frameworkcode );
311 # modify the other koha tables
312 _koha_modify_biblio( $dbh, $oldbiblio, $frameworkcode );
313 _koha_modify_biblioitem_nonmarc( $dbh, $oldbiblio );
317 =head2 ModBiblioframework
319 ModBiblioframework($biblionumber,$frameworkcode);
320 Exported function to modify a biblio framework
324 sub ModBiblioframework {
325 my ( $biblionumber, $frameworkcode ) = @_;
326 my $dbh = C4::Context->dbh;
327 my $sth = $dbh->prepare(
328 "UPDATE biblio SET frameworkcode=? WHERE biblionumber=?"
330 $sth->execute($frameworkcode, $biblionumber);
338 my $error = &DelBiblio($dbh,$biblionumber);
339 Exported function (core API) for deleting a biblio in koha.
340 Deletes biblio record from Zebra and Koha tables (biblio,biblioitems,items)
341 Also backs it up to deleted* tables
342 Checks to make sure there are not issues on any of the items
344 C<$error> : undef unless an error occurs
351 my ( $biblionumber ) = @_;
352 my $dbh = C4::Context->dbh;
353 my $error; # for error handling
355 # First make sure this biblio has no items attached
356 my $sth = $dbh->prepare("SELECT itemnumber FROM items WHERE biblionumber=?");
357 $sth->execute($biblionumber);
358 if (my $itemnumber = $sth->fetchrow){
359 # Fix this to use a status the template can understand
360 $error .= "This Biblio has items attached, please delete them first before deleting this biblio ";
363 return $error if $error;
365 # Delete in Zebra. Be careful NOT to move this line after _koha_delete_biblio
366 # for at least 2 reasons :
367 # - we need to read the biblio if NoZebra is set (to remove it from the indexes
368 # - if something goes wrong, the biblio may be deleted from Koha but not from zebra
369 # and we would have no way to remove it (except manually in zebra, but I bet it would be very hard to handle the problem)
371 if (C4::Context->preference("NoZebra")) {
372 # only NoZebra indexing needs to have
373 # the previous version of the record
374 $oldRecord = GetMarcBiblio($biblionumber);
376 ModZebra($biblionumber, "recordDelete", "biblioserver", $oldRecord, undef);
378 # delete biblioitems and items from Koha tables and save in deletedbiblioitems,deleteditems
381 "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
382 $sth->execute($biblionumber);
383 while ( my $biblioitemnumber = $sth->fetchrow ) {
385 # delete this biblioitem
386 $error = _koha_delete_biblioitems( $dbh, $biblioitemnumber );
387 return $error if $error;
390 # delete biblio from Koha tables and save in deletedbiblio
391 # must do this *after* _koha_delete_biblioitems, otherwise
392 # delete cascade will prevent deletedbiblioitems rows
393 # from being generated by _koha_delete_biblioitems
394 $error = _koha_delete_biblio( $dbh, $biblionumber );
396 logaction("CATALOGUING", "DELETE", $biblionumber, "") if C4::Context->preference("CataloguingLog");
401 =head2 LinkBibHeadingsToAuthorities
405 my $headings_linked = LinkBibHeadingsToAuthorities($marc);
409 Links bib headings to authority records by checking
410 each authority-controlled field in the C<MARC::Record>
411 object C<$marc>, looking for a matching authority record,
412 and setting the linking subfield $9 to the ID of that
415 If no matching authority exists, or if multiple
416 authorities match, no $9 will be added, and any
417 existing one inthe field will be deleted.
419 Returns the number of heading links changed in the
424 sub LinkBibHeadingsToAuthorities {
427 my $num_headings_changed = 0;
428 foreach my $field ($bib->fields()) {
429 my $heading = C4::Heading->new_from_bib_field($field);
430 next unless defined $heading;
433 my $current_link = $field->subfield('9');
435 # look for matching authorities
436 my $authorities = $heading->authorities();
438 # want only one exact match
439 if ($#{ $authorities } == 0) {
440 my $authority = MARC::Record->new_from_usmarc($authorities->[0]);
441 my $authid = $authority->field('001')->data();
442 next if defined $current_link and $current_link eq $authid;
444 $field->delete_subfield(code => '9') if defined $current_link;
445 $field->add_subfields('9', $authid);
446 $num_headings_changed++;
448 if (defined $current_link) {
449 $field->delete_subfield(code => '9');
450 $num_headings_changed++;
455 return $num_headings_changed;
462 $data = &GetBiblioData($biblionumber);
463 Returns information about the book with the given biblionumber.
464 C<&GetBiblioData> returns a reference-to-hash. The keys are the fields in
465 the C<biblio> and C<biblioitems> tables in the
467 In addition, C<$data-E<gt>{subject}> is the list of the book's
468 subjects, separated by C<" , "> (space, comma, space).
469 If there are multiple biblioitems with the given biblionumber, only
470 the first one is considered.
478 my $dbh = C4::Context->dbh;
480 # my $query = C4::Context->preference('item-level_itypes') ?
481 # " SELECT * , biblioitems.notes AS bnotes, biblio.notes
483 # LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
484 # WHERE biblio.biblionumber = ?
485 # AND biblioitems.biblionumber = biblio.biblionumber
488 my $query = " SELECT * , biblioitems.notes AS bnotes, itemtypes.notforloan as bi_notforloan, biblio.notes
490 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
491 LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
492 WHERE biblio.biblionumber = ?
493 AND biblioitems.biblionumber = biblio.biblionumber ";
495 my $sth = $dbh->prepare($query);
496 $sth->execute($bibnum);
498 $data = $sth->fetchrow_hashref;
502 } # sub GetBiblioData
504 =head2 &GetBiblioItemData
508 $itemdata = &GetBiblioItemData($biblioitemnumber);
510 Looks up the biblioitem with the given biblioitemnumber. Returns a
511 reference-to-hash. The keys are the fields from the C<biblio>,
512 C<biblioitems>, and C<itemtypes> tables in the Koha database, except
513 that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
520 sub GetBiblioItemData {
521 my ($biblioitemnumber) = @_;
522 my $dbh = C4::Context->dbh;
523 my $query = "SELECT *,biblioitems.notes AS bnotes
524 FROM biblio LEFT JOIN biblioitems on biblio.biblionumber=biblioitems.biblionumber ";
525 unless(C4::Context->preference('item-level_itypes')) {
526 $query .= "LEFT JOIN itemtypes on biblioitems.itemtype=itemtypes.itemtype ";
528 $query .= " WHERE biblioitemnumber = ? ";
529 my $sth = $dbh->prepare($query);
531 $sth->execute($biblioitemnumber);
532 $data = $sth->fetchrow_hashref;
535 } # sub &GetBiblioItemData
537 =head2 GetBiblioItemByBiblioNumber
541 NOTE : This function has been copy/paste from C4/Biblio.pm from head before zebra integration.
547 sub GetBiblioItemByBiblioNumber {
548 my ($biblionumber) = @_;
549 my $dbh = C4::Context->dbh;
550 my $sth = $dbh->prepare("Select * FROM biblioitems WHERE biblionumber = ?");
554 $sth->execute($biblionumber);
556 while ( my $data = $sth->fetchrow_hashref ) {
557 push @results, $data;
564 =head2 GetBiblioFromItemNumber
568 $item = &GetBiblioFromItemNumber($itemnumber,$barcode);
570 Looks up the item with the given itemnumber. if undef, try the barcode.
572 C<&itemnodata> returns a reference-to-hash whose keys are the fields
573 from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
581 sub GetBiblioFromItemNumber {
582 my ( $itemnumber, $barcode ) = @_;
583 my $dbh = C4::Context->dbh;
586 $sth=$dbh->prepare( "SELECT * FROM items
587 LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
588 LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
589 WHERE items.itemnumber = ?") ;
590 $sth->execute($itemnumber);
592 $sth=$dbh->prepare( "SELECT * FROM items
593 LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
594 LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
595 WHERE items.barcode = ?") ;
596 $sth->execute($barcode);
598 my $data = $sth->fetchrow_hashref;
607 ( $count, @results ) = &GetBiblio($biblionumber);
614 my ($biblionumber) = @_;
615 my $dbh = C4::Context->dbh;
616 my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber = ?");
619 $sth->execute($biblionumber);
620 while ( my $data = $sth->fetchrow_hashref ) {
621 $results[$count] = $data;
625 return ( $count, @results );
628 =head2 GetBiblioItemInfosOf
632 GetBiblioItemInfosOf(@biblioitemnumbers);
638 sub GetBiblioItemInfosOf {
639 my @biblioitemnumbers = @_;
642 SELECT biblioitemnumber,
646 WHERE biblioitemnumber IN (' . join( ',', @biblioitemnumbers ) . ')
648 return get_infos_of( $query, 'biblioitemnumber' );
651 =head1 FUNCTIONS FOR HANDLING MARC MANAGEMENT
653 =head2 GetMarcStructure
657 $res = GetMarcStructure($forlibrarian,$frameworkcode);
659 Returns a reference to a big hash of hash, with the Marc structure for the given frameworkcode
660 $forlibrarian :if set to 1, the MARC descriptions are the librarians ones, otherwise it's the public (OPAC) ones
661 $frameworkcode : the framework code to read
667 # cache for results of GetMarcStructure -- needed
669 our $marc_structure_cache;
671 sub GetMarcStructure {
672 my ( $forlibrarian, $frameworkcode ) = @_;
673 my $dbh=C4::Context->dbh;
674 $frameworkcode = "" unless $frameworkcode;
676 if (defined $marc_structure_cache and exists $marc_structure_cache->{$forlibrarian}->{$frameworkcode}) {
677 return $marc_structure_cache->{$forlibrarian}->{$frameworkcode};
681 my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
683 # check that framework exists
686 "SELECT COUNT(*) FROM marc_tag_structure WHERE frameworkcode=?");
687 $sth->execute($frameworkcode);
688 my ($total) = $sth->fetchrow;
689 $frameworkcode = "" unless ( $total > 0 );
692 "SELECT tagfield,liblibrarian,libopac,mandatory,repeatable
693 FROM marc_tag_structure
694 WHERE frameworkcode=?
697 $sth->execute($frameworkcode);
698 my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
700 while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) =
703 $res->{$tag}->{lib} =
704 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
705 $res->{$tag}->{tab} = "";
706 $res->{$tag}->{mandatory} = $mandatory;
707 $res->{$tag}->{repeatable} = $repeatable;
712 "SELECT tagfield,tagsubfield,liblibrarian,libopac,tab,mandatory,repeatable,authorised_value,authtypecode,value_builder,kohafield,seealso,hidden,isurl,link,defaultvalue
713 FROM marc_subfield_structure
714 WHERE frameworkcode=?
715 ORDER BY tagfield,tagsubfield
719 $sth->execute($frameworkcode);
722 my $authorised_value;
734 $tag, $subfield, $liblibrarian,
736 $mandatory, $repeatable, $authorised_value,
737 $authtypecode, $value_builder, $kohafield,
738 $seealso, $hidden, $isurl,
744 $res->{$tag}->{$subfield}->{lib} =
745 ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
746 $res->{$tag}->{$subfield}->{tab} = $tab;
747 $res->{$tag}->{$subfield}->{mandatory} = $mandatory;
748 $res->{$tag}->{$subfield}->{repeatable} = $repeatable;
749 $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
750 $res->{$tag}->{$subfield}->{authtypecode} = $authtypecode;
751 $res->{$tag}->{$subfield}->{value_builder} = $value_builder;
752 $res->{$tag}->{$subfield}->{kohafield} = $kohafield;
753 $res->{$tag}->{$subfield}->{seealso} = $seealso;
754 $res->{$tag}->{$subfield}->{hidden} = $hidden;
755 $res->{$tag}->{$subfield}->{isurl} = $isurl;
756 $res->{$tag}->{$subfield}->{'link'} = $link;
757 $res->{$tag}->{$subfield}->{defaultvalue} = $defaultvalue;
760 $marc_structure_cache->{$forlibrarian}->{$frameworkcode} = $res;
765 =head2 GetUsedMarcStructure
767 the same function as GetMarcStructure expcet it just take field
768 in tab 0-9. (used field)
770 my $results = GetUsedMarcStructure($frameworkcode);
772 L<$results> is a ref to an array which each case containts a ref
773 to a hash which each keys is the columns from marc_subfield_structure
775 L<$frameworkcode> is the framework code.
779 sub GetUsedMarcStructure($){
780 my $frameworkcode = shift || '';
781 my $dbh = C4::Context->dbh;
784 FROM marc_subfield_structure
786 AND frameworkcode = ?
789 my $sth = $dbh->prepare($query);
790 $sth->execute($frameworkcode);
791 while (my $row = $sth->fetchrow_hashref){
797 =head2 GetMarcFromKohaField
801 ($MARCfield,$MARCsubfield)=GetMarcFromKohaField($kohafield,$frameworkcode);
802 Returns the MARC fields & subfields mapped to the koha field
803 for the given frameworkcode
809 sub GetMarcFromKohaField {
810 my ( $kohafield, $frameworkcode ) = @_;
811 return 0, 0 unless $kohafield and defined $frameworkcode;
812 my $relations = C4::Context->marcfromkohafield;
814 $relations->{$frameworkcode}->{$kohafield}->[0],
815 $relations->{$frameworkcode}->{$kohafield}->[1]
823 my $record = GetMarcBiblio($biblionumber);
827 Returns MARC::Record representing bib identified by
828 C<$biblionumber>. If no bib exists, returns undef.
829 The MARC record contains both biblio & item data.
834 my $biblionumber = shift;
835 my $dbh = C4::Context->dbh;
837 $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
838 $sth->execute($biblionumber);
839 my $row = $sth->fetchrow_hashref;
840 my $marcxml = StripNonXmlChars($row->{'marcxml'});
841 MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
842 my $record = MARC::Record->new();
844 $record = eval {MARC::Record::new_from_xml( $marcxml, "utf8", C4::Context->preference('marcflavour'))};
845 if ($@) {warn " problem with :$biblionumber : $@ \n$marcxml";}
846 # $record = MARC::Record::new_from_usmarc( $marc) if $marc;
857 my $marcxml = GetXmlBiblio($biblionumber);
859 Returns biblioitems.marcxml of the biblionumber passed in parameter.
860 The XML contains both biblio & item datas
867 my ( $biblionumber ) = @_;
868 my $dbh = C4::Context->dbh;
870 $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
871 $sth->execute($biblionumber);
872 my ($marcxml) = $sth->fetchrow;
876 =head2 GetCOinSBiblio
880 my $coins = GetCOinSBiblio($biblionumber);
882 Returns the COinS(a span) which can be included in a biblio record
889 my ( $biblionumber ) = @_;
890 my $record = GetMarcBiblio($biblionumber);
892 if (defined $record){
893 # get the coin format
894 my $pos7 = substr $record->leader(), 7,1;
895 my $pos6 = substr $record->leader(), 6,1;
898 my ($aulast, $aufirst);
906 if ( C4::Context->preference("marcflavour") eq "UNIMARC" ){
917 'i' => 'audioRecording',
918 'j' => 'audioRecording',
921 'm' => 'computerProgram',
926 'a' => 'journalArticle',
930 $genre = $fmts6->{$pos6} ? $fmts6->{$pos6} : 'book' ;
932 if( $genre eq 'book' ){
933 $genre = $fmts7->{$pos7} if $fmts7->{$pos7};
936 ##### We must transform mtx to a valable mtx and document type ####
937 if( $genre eq 'book' ){
939 }elsif( $genre eq 'journal' ){
941 }elsif( $genre eq 'journalArticle' ){
948 $genre = ($mtx eq 'dc') ? "&rft.type=$genre" : "&rft.genre=$genre";
951 $aulast = $record->subfield('700','a');
952 $aufirst = $record->subfield('700','b');
953 $oauthors = "&rft.au=$aufirst $aulast";
955 if($record->field('200')){
956 for my $au ($record->field('200')->subfield('g')){
957 $oauthors .= "&rft.au=$au";
960 $title = ( $mtx eq 'dc' ) ? "&rft.title=".$record->subfield('200','a') :
961 "&rft.title=".$record->subfield('200','a')."&rft.btitle=".$record->subfield('200','a');
962 $pubyear = $record->subfield('210','d');
963 $publisher = $record->subfield('210','c');
964 $isbn = $record->subfield('010','a');
965 $issn = $record->subfield('011','a');
967 # MARC21 need some improve
970 $genre = "&rft.genre=book";
973 $oauthors .= "&rft.au=".$record->subfield('100','a');
975 if($record->field('700')){
976 for my $au ($record->field('700')->subfield('a')){
977 $oauthors .= "&rft.au=$au";
980 $title = "&rft.btitle=".$record->subfield('245','a');
981 $pubyear = $record->subfield('260','c');
982 $publisher = $record->subfield('260','b');
983 $isbn = $record->subfield('020','a');
984 $issn = $record->subfield('022','a');
987 $coins_value = "ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3A$mtx$genre$title&rft.isbn=$isbn&rft.issn=$issn&rft.aulast=$aulast&rft.aufirst=$aufirst$oauthors&rft.pub=$publisher&rft.date=$pubyear";
988 $coins_value =~ s/\ /\+/g;
989 #<!-- TMPL_VAR NAME="ocoins_format" -->&rft.au=<!-- TMPL_VAR NAME="author" -->&rft.btitle=<!-- TMPL_VAR NAME="title" -->&rft.date=<!-- TMPL_VAR NAME="publicationyear" -->&rft.pages=<!-- TMPL_VAR NAME="pages" -->&rft.isbn=<!-- TMPL_VAR NAME=amazonisbn -->&rft.aucorp=&rft.place=<!-- TMPL_VAR NAME="place" -->&rft.pub=<!-- TMPL_VAR NAME="publishercode" -->&rft.edition=<!-- TMPL_VAR NAME="edition" -->&rft.series=<!-- TMPL_VAR NAME="series" -->&rft.genre="
994 =head2 GetAuthorisedValueDesc
998 my $subfieldvalue =get_authorised_value_desc(
999 $tag, $subf[$i][0],$subf[$i][1], '', $taglib, $category);
1000 Retrieve the complete description for a given authorised value.
1002 Now takes $category and $value pair too.
1003 my $auth_value_desc =GetAuthorisedValueDesc(
1004 '','', 'DVD' ,'','','CCODE');
1010 sub GetAuthorisedValueDesc {
1011 my ( $tag, $subfield, $value, $framework, $tagslib, $category ) = @_;
1012 my $dbh = C4::Context->dbh;
1016 return $value unless defined $tagslib->{$tag}->{$subfield}->{'authorised_value'};
1019 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
1020 return C4::Branch::GetBranchName($value);
1024 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "itemtypes" ) {
1025 return getitemtypeinfo($value)->{description};
1028 #---- "true" authorized value
1029 $category = $tagslib->{$tag}->{$subfield}->{'authorised_value'}
1032 if ( $category ne "" ) {
1035 "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
1037 $sth->execute( $category, $value );
1038 my $data = $sth->fetchrow_hashref;
1039 return $data->{'lib'};
1042 return $value; # if nothing is found return the original value
1050 $marcnotesarray = GetMarcNotes( $record, $marcflavour );
1051 Get all notes from the MARC record and returns them in an array.
1052 The note are stored in differents places depending on MARC flavour
1059 my ( $record, $marcflavour ) = @_;
1061 if ( $marcflavour eq "MARC21" ) {
1064 else { # assume unimarc if not marc21
1071 foreach my $field ( $record->field($scope) ) {
1072 my $value = $field->as_string();
1073 $value =~ s/\n/<br \/>/g ;
1075 if ( $note ne "" ) {
1076 $marcnote = { marcnote => $note, };
1077 push @marcnotes, $marcnote;
1080 if ( $note ne $value ) {
1081 $note = $note . " " . $value;
1086 $marcnote = { marcnote => $note };
1087 push @marcnotes, $marcnote; #load last tag into array
1090 } # end GetMarcNotes
1092 =head2 GetMarcSubjects
1096 $marcsubjcts = GetMarcSubjects($record,$marcflavour);
1097 Get all subjects from the MARC record and returns them in an array.
1098 The subjects are stored in differents places depending on MARC flavour
1104 sub GetMarcSubjects {
1105 my ( $record, $marcflavour ) = @_;
1106 my ( $mintag, $maxtag );
1107 if ( $marcflavour eq "MARC21" ) {
1111 else { # assume unimarc if not marc21
1121 foreach my $field ( $record->field('6..' )) {
1122 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1124 my @subfields = $field->subfields();
1127 # if there is an authority link, build the link with an= subfield9
1128 my $subfield9 = $field->subfield('9');
1129 for my $subject_subfield (@subfields ) {
1130 # don't load unimarc subfields 3,4,5
1131 next if (($marcflavour eq "UNIMARC") and ($subject_subfield->[0] =~ /3|4|5/ ) );
1132 my $code = $subject_subfield->[0];
1133 my $value = $subject_subfield->[1];
1134 my $linkvalue = $value;
1135 $linkvalue =~ s/(\(|\))//g;
1136 my $operator = " and " unless $counter==0;
1138 @link_loop = ({'limit' => 'an' ,link => "$subfield9" });
1140 push @link_loop, {'limit' => 'su', link => $linkvalue, operator => $operator };
1142 my $separator = C4::Context->preference("authoritysep") unless $counter==0;
1144 my @this_link_loop = @link_loop;
1145 push @subfields_loop, {code => $code, value => $value, link_loop => \@this_link_loop, separator => $separator} unless ($subject_subfield->[0] eq 9 );
1149 push @marcsubjects, { MARCSUBJECT_SUBFIELDS_LOOP => \@subfields_loop };
1152 return \@marcsubjects;
1153 } #end getMARCsubjects
1155 =head2 GetMarcAuthors
1159 authors = GetMarcAuthors($record,$marcflavour);
1160 Get all authors from the MARC record and returns them in an array.
1161 The authors are stored in differents places depending on MARC flavour
1167 sub GetMarcAuthors {
1168 my ( $record, $marcflavour ) = @_;
1169 my ( $mintag, $maxtag );
1170 # tagslib useful for UNIMARC author reponsabilities
1171 my $tagslib = &GetMarcStructure( 1, '' ); # FIXME : we don't have the framework available, we take the default framework. May be bugguy on some setups, will be usually correct.
1172 if ( $marcflavour eq "MARC21" ) {
1176 elsif ( $marcflavour eq "UNIMARC" ) { # assume unimarc if not marc21
1185 foreach my $field ( $record->fields ) {
1186 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1189 my @subfields = $field->subfields();
1191 # if there is an authority link, build the link with Koha-Auth-Number: subfield9
1192 my $subfield9 = $field->subfield('9');
1193 for my $authors_subfield (@subfields) {
1194 # don't load unimarc subfields 3, 5
1195 next if ($marcflavour eq 'UNIMARC' and ($authors_subfield->[0] =~ /3|5/ ) );
1196 my $subfieldcode = $authors_subfield->[0];
1197 my $value = $authors_subfield->[1];
1198 my $linkvalue = $value;
1199 $linkvalue =~ s/(\(|\))//g;
1200 my $operator = " and " unless $count_auth==0;
1201 # if we have an authority link, use that as the link, otherwise use standard searching
1203 @link_loop = ({'limit' => 'an' ,link => "$subfield9" });
1206 # reset $linkvalue if UNIMARC author responsibility
1207 if ( $marcflavour eq 'UNIMARC' and ($authors_subfield->[0] eq "4")) {
1208 $linkvalue = "(".GetAuthorisedValueDesc( $field->tag(), $authors_subfield->[0], $authors_subfield->[1], '', $tagslib ).")";
1210 push @link_loop, {'limit' => 'au', link => $linkvalue, operator => $operator };
1212 $value = GetAuthorisedValueDesc( $field->tag(), $authors_subfield->[0], $authors_subfield->[1], '', $tagslib ) if ( $marcflavour eq 'UNIMARC' and ($authors_subfield->[0] =~/4/));
1213 my @this_link_loop = @link_loop;
1214 my $separator = C4::Context->preference("authoritysep") unless $count_auth==0;
1215 push @subfields_loop, {code => $subfieldcode, value => $value, link_loop => \@this_link_loop, separator => $separator} unless ($authors_subfield->[0] eq '9' );
1218 push @marcauthors, { MARCAUTHOR_SUBFIELDS_LOOP => \@subfields_loop };
1220 return \@marcauthors;
1227 $marcurls = GetMarcUrls($record,$marcflavour);
1228 Returns arrayref of URLs from MARC data, suitable to pass to tmpl loop.
1229 Assumes web resources (not uncommon in MARC21 to omit resource type ind)
1236 my ($record, $marcflavour) = @_;
1238 for my $field ($record->field('856')) {
1240 my $url = $field->subfield('u');
1242 for my $note ( $field->subfield('z')) {
1243 push @notes , {note => $note};
1245 if($marcflavour eq 'MARC21') {
1246 my $s3 = $field->subfield('3');
1247 my $link = $field->subfield('y');
1248 unless($url =~ /^\w+:/) {
1249 if($field->indicator(1) eq '7') {
1250 $url = $field->subfield('2') . "://" . $url;
1251 } elsif ($field->indicator(1) eq '1') {
1252 $url = 'ftp://' . $url;
1254 # properly, this should be if ind1=4,
1255 # however we will assume http protocol since we're building a link.
1256 $url = 'http://' . $url;
1259 # TODO handle ind 2 (relationship)
1260 $marcurl = { MARCURL => $url,
1263 $marcurl->{'linktext'} = $link || $s3 || C4::Context->preference('URLLinkText') || $url ;
1264 $marcurl->{'part'} = $s3 if($link);
1265 $marcurl->{'toc'} = 1 if($s3 =~ /^[Tt]able/) ;
1267 $marcurl->{'linktext'} = $field->subfield('2') || C4::Context->preference('URLLinkText') || $url;
1268 $marcurl->{'MARCURL'} = $url ;
1270 push @marcurls, $marcurl;
1275 =head2 GetMarcSeries
1279 $marcseriesarray = GetMarcSeries($record,$marcflavour);
1280 Get all series from the MARC record and returns them in an array.
1281 The series are stored in differents places depending on MARC flavour
1288 my ($record, $marcflavour) = @_;
1289 my ($mintag, $maxtag);
1290 if ($marcflavour eq "MARC21") {
1293 } else { # assume unimarc if not marc21
1303 foreach my $field ($record->field('440'), $record->field('490')) {
1305 #my $value = $field->subfield('a');
1306 #$marcsubjct = {MARCSUBJCT => $value,};
1307 my @subfields = $field->subfields();
1308 #warn "subfields:".join " ", @$subfields;
1311 for my $series_subfield (@subfields) {
1313 undef $volume_number;
1314 # see if this is an instance of a volume
1315 if ($series_subfield->[0] eq 'v') {
1319 my $code = $series_subfield->[0];
1320 my $value = $series_subfield->[1];
1321 my $linkvalue = $value;
1322 $linkvalue =~ s/(\(|\))//g;
1323 my $operator = " and " unless $counter==0;
1324 push @link_loop, {link => $linkvalue, operator => $operator };
1325 my $separator = C4::Context->preference("authoritysep") unless $counter==0;
1326 if ($volume_number) {
1327 push @subfields_loop, {volumenum => $value};
1330 push @subfields_loop, {code => $code, value => $value, link_loop => \@link_loop, separator => $separator, volumenum => $volume_number};
1334 push @marcseries, { MARCSERIES_SUBFIELDS_LOOP => \@subfields_loop };
1335 #$marcsubjct = {MARCSUBJCT => $field->as_string(),};
1336 #push @marcsubjcts, $marcsubjct;
1340 my $marcseriessarray=\@marcseries;
1341 return $marcseriessarray;
1342 } #end getMARCseriess
1344 =head2 GetFrameworkCode
1348 $frameworkcode = GetFrameworkCode( $biblionumber )
1354 sub GetFrameworkCode {
1355 my ( $biblionumber ) = @_;
1356 my $dbh = C4::Context->dbh;
1357 my $sth = $dbh->prepare("SELECT frameworkcode FROM biblio WHERE biblionumber=?");
1358 $sth->execute($biblionumber);
1359 my ($frameworkcode) = $sth->fetchrow;
1360 return $frameworkcode;
1363 =head2 GetPublisherNameFromIsbn
1365 $name = GetPublishercodeFromIsbn($isbn);
1372 sub GetPublisherNameFromIsbn($){
1374 $isbn =~ s/[- _]//g;
1376 my @codes = (split '-', DisplayISBN($isbn));
1377 my $code = $codes[0].$codes[1].$codes[2];
1378 my $dbh = C4::Context->dbh;
1380 SELECT distinct publishercode
1383 AND publishercode IS NOT NULL
1386 my $sth = $dbh->prepare($query);
1387 $sth->execute("$code%");
1388 my $name = $sth->fetchrow;
1389 return $name if length $name;
1393 =head2 TransformKohaToMarc
1397 $record = TransformKohaToMarc( $hash )
1398 This function builds partial MARC::Record from a hash
1399 Hash entries can be from biblio or biblioitems.
1400 This function is called in acquisition module, to create a basic catalogue entry from user entry
1406 sub TransformKohaToMarc {
1409 my $dbh = C4::Context->dbh;
1412 "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE frameworkcode=? AND kohafield=?"
1414 my $record = MARC::Record->new();
1415 foreach (keys %{$hash}) {
1416 &TransformKohaToMarcOneField( $sth, $record, $_,
1422 =head2 TransformKohaToMarcOneField
1426 $record = TransformKohaToMarcOneField( $sth, $record, $kohafieldname, $value, $frameworkcode );
1432 sub TransformKohaToMarcOneField {
1433 my ( $sth, $record, $kohafieldname, $value, $frameworkcode ) = @_;
1434 $frameworkcode='' unless $frameworkcode;
1438 if ( !defined $sth ) {
1439 my $dbh = C4::Context->dbh;
1440 $sth = $dbh->prepare(
1441 "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE frameworkcode=? AND kohafield=?"
1444 $sth->execute( $frameworkcode, $kohafieldname );
1445 if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
1446 my $tag = $record->field($tagfield);
1448 $tag->update( $tagsubfield => $value );
1449 $record->delete_field($tag);
1450 $record->insert_fields_ordered($tag);
1453 $record->add_fields( $tagfield, " ", " ", $tagsubfield => $value );
1459 =head2 TransformHtmlToXml
1463 $xml = TransformHtmlToXml( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type )
1465 $auth_type contains :
1466 - nothing : rebuild a biblio, un UNIMARC the encoding is in 100$a pos 26/27
1467 - UNIMARCAUTH : rebuild an authority. In UNIMARC, the encoding is in 100$a pos 13/14
1468 - ITEM : rebuild an item : in UNIMARC, 100$a, it's in the biblio ! (otherwise, we would get 2 100 fields !)
1474 sub TransformHtmlToXml {
1475 my ( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type ) = @_;
1476 my $xml = MARC::File::XML::header('UTF-8');
1477 $auth_type = C4::Context->preference('marcflavour') unless $auth_type;
1478 MARC::File::XML->default_record_format($auth_type);
1479 # in UNIMARC, field 100 contains the encoding
1480 # check that there is one, otherwise the
1481 # MARC::Record->new_from_xml will fail (and Koha will die)
1482 my $unimarc_and_100_exist=0;
1483 $unimarc_and_100_exist=1 if $auth_type eq 'ITEM'; # if we rebuild an item, no need of a 100 field
1488 for ( my $i = 0 ; $i < @$tags ; $i++ ) {
1489 if (C4::Context->preference('marcflavour') eq 'UNIMARC' and @$tags[$i] eq "100" and @$subfields[$i] eq "a") {
1490 # if we have a 100 field and it's values are not correct, skip them.
1491 # if we don't have any valid 100 field, we will create a default one at the end
1492 my $enc = substr( @$values[$i], 26, 2 );
1493 if ($enc eq '01' or $enc eq '50' or $enc eq '03') {
1494 $unimarc_and_100_exist=1;
1499 @$values[$i] =~ s/&/&/g;
1500 @$values[$i] =~ s/</</g;
1501 @$values[$i] =~ s/>/>/g;
1502 @$values[$i] =~ s/"/"/g;
1503 @$values[$i] =~ s/'/'/g;
1504 # if ( !utf8::is_utf8( @$values[$i] ) ) {
1505 # utf8::decode( @$values[$i] );
1507 if ( ( @$tags[$i] ne $prevtag ) ) {
1508 $j++ unless ( @$tags[$i] eq "" );
1510 $xml .= "</datafield>\n";
1511 if ( ( @$tags[$i] && @$tags[$i] > 10 )
1512 && ( @$values[$i] ne "" ) )
1514 my $ind1 = substr( @$indicator[$j], 0, 1 );
1516 if ( @$indicator[$j] ) {
1517 $ind2 = substr( @$indicator[$j], 1, 1 );
1520 warn "Indicator in @$tags[$i] is empty";
1524 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1526 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1534 if ( @$values[$i] ne "" ) {
1537 if ( @$tags[$i] eq "000" ) {
1538 $xml .= "<leader>@$values[$i]</leader>\n";
1541 # rest of the fixed fields
1543 elsif ( @$tags[$i] < 10 ) {
1545 "<controlfield tag=\"@$tags[$i]\">@$values[$i]</controlfield>\n";
1549 my $ind1 = substr( @$indicator[$j], 0, 1 );
1550 my $ind2 = substr( @$indicator[$j], 1, 1 );
1552 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1554 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1560 else { # @$tags[$i] eq $prevtag
1561 if ( @$values[$i] eq "" ) {
1565 my $ind1 = substr( @$indicator[$j], 0, 1 );
1566 my $ind2 = substr( @$indicator[$j], 1, 1 );
1568 "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
1572 "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
1575 $prevtag = @$tags[$i];
1577 $xml .= "</datafield>\n" if @$tags > 0;
1578 if (C4::Context->preference('marcflavour') eq 'UNIMARC' and !$unimarc_and_100_exist) {
1579 # warn "SETTING 100 for $auth_type";
1580 use POSIX qw(strftime);
1581 my $string = strftime( "%Y%m%d", localtime(time) );
1582 # set 50 to position 26 is biblios, 13 if authorities
1584 $pos=13 if $auth_type eq 'UNIMARCAUTH';
1585 $string = sprintf( "%-*s", 35, $string );
1586 substr( $string, $pos , 6, "50" );
1587 $xml .= "<datafield tag=\"100\" ind1=\"\" ind2=\"\">\n";
1588 $xml .= "<subfield code=\"a\">$string</subfield>\n";
1589 $xml .= "</datafield>\n";
1591 $xml .= MARC::File::XML::footer();
1595 =head2 TransformHtmlToMarc
1597 L<$record> = TransformHtmlToMarc(L<$params>,L<$cgi>)
1598 L<$params> is a ref to an array as below:
1600 'tag_010_indicator1_531951' ,
1601 'tag_010_indicator2_531951' ,
1602 'tag_010_code_a_531951_145735' ,
1603 'tag_010_subfield_a_531951_145735' ,
1604 'tag_200_indicator1_873510' ,
1605 'tag_200_indicator2_873510' ,
1606 'tag_200_code_a_873510_673465' ,
1607 'tag_200_subfield_a_873510_673465' ,
1608 'tag_200_code_b_873510_704318' ,
1609 'tag_200_subfield_b_873510_704318' ,
1610 'tag_200_code_e_873510_280822' ,
1611 'tag_200_subfield_e_873510_280822' ,
1612 'tag_200_code_f_873510_110730' ,
1613 'tag_200_subfield_f_873510_110730' ,
1615 L<$cgi> is the CGI object which containts the value.
1616 L<$record> is the MARC::Record object.
1620 sub TransformHtmlToMarc {
1624 # explicitly turn on the UTF-8 flag for all
1625 # 'tag_' parameters to avoid incorrect character
1626 # conversion later on
1627 my $cgi_params = $cgi->Vars;
1628 foreach my $param_name (keys %$cgi_params) {
1629 if ($param_name =~ /^tag_/) {
1630 my $param_value = $cgi_params->{$param_name};
1631 if (utf8::decode($param_value)) {
1632 $cgi_params->{$param_name} = $param_value;
1634 # FIXME - need to do something if string is not valid UTF-8
1638 # creating a new record
1639 my $record = MARC::Record->new();
1642 while ($params->[$i]){ # browse all CGI params
1643 my $param = $params->[$i];
1645 # if we are on biblionumber, store it in the MARC::Record (it may not be in the edited fields)
1646 if ($param eq 'biblionumber') {
1647 my ( $biblionumbertagfield, $biblionumbertagsubfield ) =
1648 &GetMarcFromKohaField( "biblio.biblionumber", '' );
1649 if ($biblionumbertagfield < 10) {
1650 $newfield = MARC::Field->new(
1651 $biblionumbertagfield,
1652 $cgi->param($param),
1655 $newfield = MARC::Field->new(
1656 $biblionumbertagfield,
1659 "$biblionumbertagsubfield" => $cgi->param($param),
1662 push @fields,$newfield if($newfield);
1664 elsif ($param =~ /^tag_(\d*)_indicator1_/){ # new field start when having 'input name="..._indicator1_..."
1667 my $ind1 = substr($cgi->param($param),0,1);
1668 my $ind2 = substr($cgi->param($params->[$i+1]),0,1);
1672 if($tag < 10){ # no code for theses fields
1673 # in MARC editor, 000 contains the leader.
1674 if ($tag eq '000' ) {
1675 $record->leader($cgi->param($params->[$j+1])) if length($cgi->param($params->[$j+1]))==24;
1676 # between 001 and 009 (included)
1677 } elsif ($cgi->param($params->[$j+1]) ne '') {
1678 $newfield = MARC::Field->new(
1680 $cgi->param($params->[$j+1]),
1683 # > 009, deal with subfields
1685 while(defined $params->[$j] && $params->[$j] =~ /_code_/){ # browse all it's subfield
1686 my $inner_param = $params->[$j];
1688 if($cgi->param($params->[$j+1]) ne ''){ # only if there is a value (code => value)
1689 $newfield->add_subfields(
1690 $cgi->param($inner_param) => $cgi->param($params->[$j+1])
1694 if ( $cgi->param($params->[$j+1]) ne '' ) { # creating only if there is a value (code => value)
1695 $newfield = MARC::Field->new(
1699 $cgi->param($inner_param) => $cgi->param($params->[$j+1]),
1706 push @fields,$newfield if($newfield);
1711 $record->append_fields(@fields);
1715 # cache inverted MARC field map
1716 our $inverted_field_map;
1718 =head2 TransformMarcToKoha
1722 $result = TransformMarcToKoha( $dbh, $record, $frameworkcode )
1726 Extract data from a MARC bib record into a hashref representing
1727 Koha biblio, biblioitems, and items fields.
1730 sub TransformMarcToKoha {
1731 my ( $dbh, $record, $frameworkcode, $limit_table ) = @_;
1734 $limit_table=$limit_table||0;
1735 $frameworkcode = '' unless defined $frameworkcode;
1737 unless (defined $inverted_field_map) {
1738 $inverted_field_map = _get_inverted_marc_field_map();
1742 if ( defined $limit_table && $limit_table eq 'items') {
1743 $tables{'items'} = 1;
1745 $tables{'items'} = 1;
1746 $tables{'biblio'} = 1;
1747 $tables{'biblioitems'} = 1;
1750 # traverse through record
1751 MARCFIELD: foreach my $field ($record->fields()) {
1752 my $tag = $field->tag();
1753 next MARCFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag};
1754 if ($field->is_control_field()) {
1755 my $kohafields = $inverted_field_map->{$frameworkcode}->{$tag}->{list};
1756 ENTRY: foreach my $entry (@{ $kohafields }) {
1757 my ($subfield, $table, $column) = @{ $entry };
1758 next ENTRY unless exists $tables{$table};
1759 my $key = _disambiguate($table, $column);
1760 if ($result->{$key}) {
1761 unless (($key eq "biblionumber" or $key eq "biblioitemnumber") and ($field->data() eq "")) {
1762 $result->{$key} .= " | " . $field->data();
1765 $result->{$key} = $field->data();
1769 # deal with subfields
1770 MARCSUBFIELD: foreach my $sf ($field->subfields()) {
1771 my $code = $sf->[0];
1772 next MARCSUBFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code};
1773 my $value = $sf->[1];
1774 SFENTRY: foreach my $entry (@{ $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code} }) {
1775 my ($table, $column) = @{ $entry };
1776 next SFENTRY unless exists $tables{$table};
1777 my $key = _disambiguate($table, $column);
1778 if ($result->{$key}) {
1779 unless (($key eq "biblionumber" or $key eq "biblioitemnumber") and ($value eq "")) {
1780 $result->{$key} .= " | " . $value;
1783 $result->{$key} = $value;
1790 # modify copyrightdate to keep only the 1st year found
1791 if (exists $result->{'copyrightdate'}) {
1792 my $temp = $result->{'copyrightdate'};
1793 $temp =~ m/c(\d\d\d\d)/;
1794 if ( $temp =~ m/c(\d\d\d\d)/ and $1 > 0 ) { # search cYYYY first
1795 $result->{'copyrightdate'} = $1;
1797 else { # if no cYYYY, get the 1st date.
1798 $temp =~ m/(\d\d\d\d)/;
1799 $result->{'copyrightdate'} = $1;
1803 # modify publicationyear to keep only the 1st year found
1804 if (exists $result->{'publicationyear'}) {
1805 my $temp = $result->{'publicationyear'};
1806 if ( $temp =~ m/c(\d\d\d\d)/ and $1 > 0 ) { # search cYYYY first
1807 $result->{'publicationyear'} = $1;
1809 else { # if no cYYYY, get the 1st date.
1810 $temp =~ m/(\d\d\d\d)/;
1811 $result->{'publicationyear'} = $1;
1818 sub _get_inverted_marc_field_map {
1820 my $relations = C4::Context->marcfromkohafield;
1822 foreach my $frameworkcode (keys %{ $relations }) {
1823 foreach my $kohafield (keys %{ $relations->{$frameworkcode} }) {
1824 next unless @{ $relations->{$frameworkcode}->{$kohafield} }; # not all columns are mapped to MARC tag & subfield
1825 my $tag = $relations->{$frameworkcode}->{$kohafield}->[0];
1826 my $subfield = $relations->{$frameworkcode}->{$kohafield}->[1];
1827 my ($table, $column) = split /[.]/, $kohafield, 2;
1828 push @{ $field_map->{$frameworkcode}->{$tag}->{list} }, [ $subfield, $table, $column ];
1829 push @{ $field_map->{$frameworkcode}->{$tag}->{sfs}->{$subfield} }, [ $table, $column ];
1835 =head2 _disambiguate
1839 $newkey = _disambiguate($table, $field);
1841 This is a temporary hack to distinguish between the
1842 following sets of columns when using TransformMarcToKoha.
1844 items.cn_source & biblioitems.cn_source
1845 items.cn_sort & biblioitems.cn_sort
1847 Columns that are currently NOT distinguished (FIXME
1848 due to lack of time to fully test) are:
1850 biblio.notes and biblioitems.notes
1855 FIXME - this is necessary because prefixing each column
1856 name with the table name would require changing lots
1857 of code and templates, and exposing more of the DB
1858 structure than is good to the UI templates, particularly
1859 since biblio and bibloitems may well merge in a future
1860 version. In the future, it would also be good to
1861 separate DB access and UI presentation field names
1869 my ($table, $column) = @_;
1870 if ($column eq "cn_sort" or $column eq "cn_source") {
1871 return $table . '.' . $column;
1878 =head2 get_koha_field_from_marc
1882 $result->{_disambiguate($table, $field)} = get_koha_field_from_marc($table,$field,$record,$frameworkcode);
1884 Internal function to map data from the MARC record to a specific non-MARC field.
1885 FIXME: this is meant to replace TransformMarcToKohaOneField after more testing.
1891 sub get_koha_field_from_marc {
1892 my ($koha_table,$koha_column,$record,$frameworkcode) = @_;
1893 my ( $tagfield, $subfield ) = GetMarcFromKohaField( $koha_table.'.'.$koha_column, $frameworkcode );
1895 foreach my $field ( $record->field($tagfield) ) {
1896 if ( $field->tag() < 10 ) {
1898 $kohafield .= " | " . $field->data();
1901 $kohafield = $field->data();
1905 if ( $field->subfields ) {
1906 my @subfields = $field->subfields();
1907 foreach my $subfieldcount ( 0 .. $#subfields ) {
1908 if ( $subfields[$subfieldcount][0] eq $subfield ) {
1911 " | " . $subfields[$subfieldcount][1];
1915 $subfields[$subfieldcount][1];
1926 =head2 TransformMarcToKohaOneField
1930 $result = TransformMarcToKohaOneField( $kohatable, $kohafield, $record, $result, $frameworkcode )
1936 sub TransformMarcToKohaOneField {
1938 # FIXME ? if a field has a repeatable subfield that is used in old-db,
1939 # only the 1st will be retrieved...
1940 my ( $kohatable, $kohafield, $record, $result, $frameworkcode ) = @_;
1942 my ( $tagfield, $subfield ) =
1943 GetMarcFromKohaField( $kohatable . "." . $kohafield,
1945 foreach my $field ( $record->field($tagfield) ) {
1946 if ( $field->tag() < 10 ) {
1947 if ( $result->{$kohafield} ) {
1948 $result->{$kohafield} .= " | " . $field->data();
1951 $result->{$kohafield} = $field->data();
1955 if ( $field->subfields ) {
1956 my @subfields = $field->subfields();
1957 foreach my $subfieldcount ( 0 .. $#subfields ) {
1958 if ( $subfields[$subfieldcount][0] eq $subfield ) {
1959 if ( $result->{$kohafield} ) {
1960 $result->{$kohafield} .=
1961 " | " . $subfields[$subfieldcount][1];
1964 $result->{$kohafield} =
1965 $subfields[$subfieldcount][1];
1975 =head1 OTHER FUNCTIONS
1978 =head2 PrepareItemrecordDisplay
1982 PrepareItemrecordDisplay($itemrecord,$bibnum,$itemumber);
1984 Returns a hash with all the fields for Display a given item data in a template
1990 sub PrepareItemrecordDisplay {
1992 my ( $bibnum, $itemnum, $defaultvalues ) = @_;
1994 my $dbh = C4::Context->dbh;
1995 my $frameworkcode = &GetFrameworkCode( $bibnum );
1996 my ( $itemtagfield, $itemtagsubfield ) =
1997 &GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
1998 my $tagslib = &GetMarcStructure( 1, $frameworkcode );
1999 my $itemrecord = C4::Items::GetMarcItem( $bibnum, $itemnum) if ($itemnum);
2001 my $authorised_values_sth =
2003 "SELECT authorised_value,lib FROM authorised_values WHERE category=? ORDER BY lib"
2005 foreach my $tag ( sort keys %{$tagslib} ) {
2006 my $previous_tag = '';
2008 # loop through each subfield
2010 foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
2011 next if ( subfield_is_koha_internal_p($subfield) );
2012 next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
2014 $subfield_data{tag} = $tag;
2015 $subfield_data{subfield} = $subfield;
2016 $subfield_data{countsubfield} = $cntsubf++;
2017 $subfield_data{kohafield} =
2018 $tagslib->{$tag}->{$subfield}->{'kohafield'};
2020 # $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
2021 $subfield_data{marc_lib} = $tagslib->{$tag}->{$subfield}->{lib};
2022 $subfield_data{mandatory} =
2023 $tagslib->{$tag}->{$subfield}->{mandatory};
2024 $subfield_data{repeatable} =
2025 $tagslib->{$tag}->{$subfield}->{repeatable};
2026 $subfield_data{hidden} = "display:none"
2027 if $tagslib->{$tag}->{$subfield}->{hidden};
2029 ( $x, $value ) = _find_value( $tag, $subfield, $itemrecord )
2031 $value =~ s/"/"/g;
2033 # search for itemcallnumber if applicable
2034 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
2035 'items.itemcallnumber'
2036 && C4::Context->preference('itemcallnumber') )
2039 substr( C4::Context->preference('itemcallnumber'), 0, 3 );
2041 substr( C4::Context->preference('itemcallnumber'), 3, 1 );
2042 my $temp = $itemrecord->field($CNtag) if ($itemrecord);
2044 $value = $temp->subfield($CNsubfield);
2047 if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
2048 'items.itemcallnumber'
2049 && $defaultvalues->{'callnumber'} )
2051 my $temp = $itemrecord->field($subfield) if ($itemrecord);
2053 $value = $defaultvalues->{'callnumber'};
2056 if ( ($tagslib->{$tag}->{$subfield}->{kohafield} eq
2057 'items.holdingbranch' ||
2058 $tagslib->{$tag}->{$subfield}->{kohafield} eq
2060 && $defaultvalues->{'branchcode'} )
2062 my $temp = $itemrecord->field($subfield) if ($itemrecord);
2064 $value = $defaultvalues->{branchcode};
2067 if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
2068 my @authorised_values;
2071 # builds list, depending on authorised value...
2073 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq
2076 if ( ( C4::Context->preference("IndependantBranches") )
2077 && ( C4::Context->userenv->{flags} != 1 ) )
2081 "SELECT branchcode,branchname FROM branches WHERE branchcode = ? ORDER BY branchname"
2083 $sth->execute( C4::Context->userenv->{branch} );
2084 push @authorised_values, ""
2086 $tagslib->{$tag}->{$subfield}->{mandatory} );
2087 while ( my ( $branchcode, $branchname ) =
2088 $sth->fetchrow_array )
2090 push @authorised_values, $branchcode;
2091 $authorised_lib{$branchcode} = $branchname;
2097 "SELECT branchcode,branchname FROM branches ORDER BY branchname"
2100 push @authorised_values, ""
2102 $tagslib->{$tag}->{$subfield}->{mandatory} );
2103 while ( my ( $branchcode, $branchname ) =
2104 $sth->fetchrow_array )
2106 push @authorised_values, $branchcode;
2107 $authorised_lib{$branchcode} = $branchname;
2113 elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq
2118 "SELECT itemtype,description FROM itemtypes ORDER BY description"
2121 push @authorised_values, ""
2122 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2123 while ( my ( $itemtype, $description ) =
2124 $sth->fetchrow_array )
2126 push @authorised_values, $itemtype;
2127 $authorised_lib{$itemtype} = $description;
2130 #---- "true" authorised value
2133 $authorised_values_sth->execute(
2134 $tagslib->{$tag}->{$subfield}->{authorised_value} );
2135 push @authorised_values, ""
2136 unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
2137 while ( my ( $value, $lib ) =
2138 $authorised_values_sth->fetchrow_array )
2140 push @authorised_values, $value;
2141 $authorised_lib{$value} = $lib;
2144 $subfield_data{marc_value} = CGI::scrolling_list(
2145 -name => 'field_value',
2146 -values => \@authorised_values,
2147 -default => "$value",
2148 -labels => \%authorised_lib,
2154 elsif ( $tagslib->{$tag}->{$subfield}->{thesaurus_category} ) {
2155 $subfield_data{marc_value} =
2156 "<input type=\"text\" name=\"field_value\" size=\"47\" maxlength=\"255\" /> <a href=\"javascript:Dopop('cataloguing/thesaurus_popup.pl?category=$tagslib->{$tag}->{$subfield}->{thesaurus_category}&index=',)\">...</a>";
2159 # COMMENTED OUT because No $i is provided with this API.
2160 # And thus, no value_builder can be activated.
2161 # BUT could be thought over.
2162 # } elsif ($tagslib->{$tag}->{$subfield}->{'value_builder'}) {
2163 # my $plugin="value_builder/".$tagslib->{$tag}->{$subfield}->{'value_builder'};
2165 # my $extended_param = plugin_parameters($dbh,$itemrecord,$tagslib,$i,0);
2166 # my ($function_name,$javascript) = plugin_javascript($dbh,$record,$tagslib,$i,0);
2167 # $subfield_data{marc_value}="<input type=\"text\" value=\"$value\" name=\"field_value\" size=47 maxlength=255 DISABLE READONLY OnFocus=\"javascript:Focus$function_name()\" OnBlur=\"javascript:Blur$function_name()\"> <a href=\"javascript:Clic$function_name()\">...</a> $javascript";
2170 $subfield_data{marc_value} =
2171 "<input type=\"text\" name=\"field_value\" value=\"$value\" size=\"50\" maxlength=\"255\" />";
2173 push( @loop_data, \%subfield_data );
2177 my $itemnumber = $itemrecord->subfield( $itemtagfield, $itemtagsubfield )
2178 if ( $itemrecord && $itemrecord->field($itemtagfield) );
2180 'itemtagfield' => $itemtagfield,
2181 'itemtagsubfield' => $itemtagsubfield,
2182 'itemnumber' => $itemnumber,
2183 'iteminformation' => \@loop_data
2189 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2191 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2192 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2193 # =head2 ModZebrafiles
2195 # &ModZebrafiles( $dbh, $biblionumber, $record, $folder, $server );
2199 # sub ModZebrafiles {
2201 # my ( $dbh, $biblionumber, $record, $folder, $server ) = @_;
2205 # C4::Context->zebraconfig($server)->{directory} . "/" . $folder . "/";
2206 # unless ( opendir( DIR, "$zebradir" ) ) {
2207 # warn "$zebradir not found";
2211 # my $filename = $zebradir . $biblionumber;
2214 # open( OUTPUT, ">", $filename . ".xml" );
2215 # print OUTPUT $record;
2224 ModZebra( $biblionumber, $op, $server, $oldRecord, $newRecord );
2226 $biblionumber is the biblionumber we want to index
2227 $op is specialUpdate or delete, and is used to know what we want to do
2228 $server is the server that we want to update
2229 $oldRecord is the MARC::Record containing the previous version of the record. This is used only when
2230 NoZebra=1, as NoZebra indexing needs to know the previous version of a record in order to
2232 $newRecord is the MARC::Record containing the new record. It is usefull only when NoZebra=1, and is used to know what to add to the nozebra database. (the record in mySQL being, if it exist, the previous record, the one just before the modif. We need both : the previous and the new one.
2239 ###Accepts a $server variable thus we can use it for biblios authorities or other zebra dbs
2240 my ( $biblionumber, $op, $server, $oldRecord, $newRecord ) = @_;
2241 my $dbh=C4::Context->dbh;
2243 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2245 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2246 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2248 if (C4::Context->preference("NoZebra")) {
2249 # lock the nozebra table : we will read index lines, update them in Perl process
2250 # and write everything in 1 transaction.
2251 # lock the table to avoid someone else overwriting what we are doing
2252 $dbh->do('LOCK TABLES nozebra WRITE,biblio WRITE,biblioitems WRITE, systempreferences WRITE, auth_types WRITE, auth_header WRITE, auth_subfield_structure READ');
2253 my %result; # the result hash that will be built by deletion / add, and written on mySQL at the end, to improve speed
2254 if ($op eq 'specialUpdate') {
2255 # OK, we have to add or update the record
2256 # 1st delete (virtually, in indexes), if record actually exists
2258 %result = _DelBiblioNoZebra($biblionumber,$oldRecord,$server);
2260 # ... add the record
2261 %result=_AddBiblioNoZebra($biblionumber,$newRecord, $server, %result);
2263 # it's a deletion, delete the record...
2264 # warn "DELETE the record $biblionumber on $server".$record->as_formatted;
2265 %result=_DelBiblioNoZebra($biblionumber,$oldRecord,$server);
2267 # ok, now update the database...
2268 my $sth = $dbh->prepare("UPDATE nozebra SET biblionumbers=? WHERE server=? AND indexname=? AND value=?");
2269 foreach my $key (keys %result) {
2270 foreach my $index (keys %{$result{$key}}) {
2271 $sth->execute($result{$key}->{$index}, $server, $key, $index);
2274 $dbh->do('UNLOCK TABLES');
2277 # we use zebra, just fill zebraqueue table
2279 my $check_sql = "SELECT COUNT(*) FROM zebraqueue
2281 AND biblio_auth_number = ?
2284 my $check_sth = $dbh->prepare_cached($check_sql);
2285 $check_sth->execute($server, $biblionumber, $op);
2286 my ($count) = $check_sth->fetchrow_array;
2287 $check_sth->finish();
2289 my $sth=$dbh->prepare("INSERT INTO zebraqueue (biblio_auth_number,server,operation) VALUES(?,?,?)");
2290 $sth->execute($biblionumber,$server,$op);
2296 =head2 GetNoZebraIndexes
2298 %indexes = GetNoZebraIndexes;
2300 return the data from NoZebraIndexes syspref.
2304 sub GetNoZebraIndexes {
2305 my $no_zebra_indexes = C4::Context->preference('NoZebraIndexes');
2307 INDEX: foreach my $line (split /['"],[\n\r]*/,$no_zebra_indexes) {
2308 $line =~ /(.*)=>(.*)/;
2309 my $index = $1; # initial ' or " is removed afterwards
2311 $index =~ s/'|"|\s//g;
2312 $fields =~ s/'|"|\s//g;
2313 $indexes{$index}=$fields;
2318 =head1 INTERNAL FUNCTIONS
2320 =head2 _DelBiblioNoZebra($biblionumber,$record,$server);
2322 function to delete a biblio in NoZebra indexes
2323 This function does NOT delete anything in database : it reads all the indexes entries
2324 that have to be deleted & delete them in the hash
2325 The SQL part is done either :
2326 - after the Add if we are modifying a biblio (delete + add again)
2327 - immediatly after this sub if we are doing a true deletion.
2328 $server can be 'biblioserver' or 'authorityserver' : it indexes biblios or authorities (in the same table, $server being part of the table itself
2333 sub _DelBiblioNoZebra {
2334 my ($biblionumber, $record, $server)=@_;
2337 my $dbh = C4::Context->dbh;
2341 if ($server eq 'biblioserver') {
2342 %index=GetNoZebraIndexes;
2343 # get title of the record (to store the 10 first letters with the index)
2344 my ($titletag,$titlesubfield) = GetMarcFromKohaField('biblio.title','');
2345 $title = lc($record->subfield($titletag,$titlesubfield));
2347 # for authorities, the "title" is the $a mainentry
2348 my ($auth_type_tag, $auth_type_sf) = C4::AuthoritiesMarc::get_auth_type_location();
2349 my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield($auth_type_tag, $auth_type_sf));
2350 warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
2351 $title = $record->subfield($authref->{auth_tag_to_report},'a');
2352 $index{'mainmainentry'}= $authref->{'auth_tag_to_report'}.'a';
2353 $index{'mainentry'} = $authref->{'auth_tag_to_report'}.'*';
2354 $index{'auth_type'} = "${auth_type_tag}${auth_type_sf}";
2358 # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
2359 $title =~ s/ |,|;|\[|\]|\(|\)|\*|-|'|=//g;
2360 # limit to 10 char, should be enough, and limit the DB size
2361 $title = substr($title,0,10);
2363 my $sth2=$dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
2364 foreach my $field ($record->fields()) {
2365 #parse each subfield
2366 next if $field->tag <10;
2367 foreach my $subfield ($field->subfields()) {
2368 my $tag = $field->tag();
2369 my $subfieldcode = $subfield->[0];
2371 # check each index to see if the subfield is stored somewhere
2372 # otherwise, store it in __RAW__ index
2373 foreach my $key (keys %index) {
2374 # warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
2375 if ($index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/) {
2377 my $line= lc $subfield->[1];
2378 # remove meaningless value in the field...
2379 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
2380 # ... and split in words
2381 foreach (split / /,$line) {
2382 next unless $_; # skip empty values (multiple spaces)
2383 # if the entry is already here, do nothing, the biblionumber has already be removed
2384 unless ( defined( $result{$key}->{$_} ) && ( $result{$key}->{$_} =~ /$biblionumber,$title\-(\d);/) ) {
2385 # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
2386 $sth2->execute($server,$key,$_);
2387 my $existing_biblionumbers = $sth2->fetchrow;
2389 if ($existing_biblionumbers) {
2390 # warn " existing for $key $_: $existing_biblionumbers";
2391 $result{$key}->{$_} =$existing_biblionumbers;
2392 $result{$key}->{$_} =~ s/$biblionumber,$title\-(\d);//;
2398 # the subfield is not indexed, store it in __RAW__ index anyway
2400 my $line= lc $subfield->[1];
2401 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
2402 # ... and split in words
2403 foreach (split / /,$line) {
2404 next unless $_; # skip empty values (multiple spaces)
2405 # if the entry is already here, do nothing, the biblionumber has already be removed
2406 unless ($result{'__RAW__'}->{$_} =~ /$biblionumber,$title\-(\d);/) {
2407 # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
2408 $sth2->execute($server,'__RAW__',$_);
2409 my $existing_biblionumbers = $sth2->fetchrow;
2411 if ($existing_biblionumbers) {
2412 $result{'__RAW__'}->{$_} =$existing_biblionumbers;
2413 $result{'__RAW__'}->{$_} =~ s/$biblionumber,$title\-(\d);//;
2423 =head2 _AddBiblioNoZebra($biblionumber, $record, $server, %result);
2425 function to add a biblio in NoZebra indexes
2429 sub _AddBiblioNoZebra {
2430 my ($biblionumber, $record, $server, %result)=@_;
2431 my $dbh = C4::Context->dbh;
2435 if ($server eq 'biblioserver') {
2436 %index=GetNoZebraIndexes;
2437 # get title of the record (to store the 10 first letters with the index)
2438 my ($titletag,$titlesubfield) = GetMarcFromKohaField('biblio.title','');
2439 $title = lc($record->subfield($titletag,$titlesubfield));
2441 # warn "server : $server";
2442 # for authorities, the "title" is the $a mainentry
2443 my ($auth_type_tag, $auth_type_sf) = C4::AuthoritiesMarc::get_auth_type_location();
2444 my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield($auth_type_tag, $auth_type_sf));
2445 warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
2446 $title = $record->subfield($authref->{auth_tag_to_report},'a');
2447 $index{'mainmainentry'} = $authref->{auth_tag_to_report}.'a';
2448 $index{'mainentry'} = $authref->{auth_tag_to_report}.'*';
2449 $index{'auth_type'} = "${auth_type_tag}${auth_type_sf}";
2452 # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
2453 $title =~ s/ |\.|,|;|\[|\]|\(|\)|\*|-|'|:|=|\r|\n//g;
2454 # limit to 10 char, should be enough, and limit the DB size
2455 $title = substr($title,0,10);
2457 my $sth2=$dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
2458 foreach my $field ($record->fields()) {
2459 #parse each subfield
2460 ###FIXME: impossible to index a 001-009 value with NoZebra
2461 next if $field->tag <10;
2462 foreach my $subfield ($field->subfields()) {
2463 my $tag = $field->tag();
2464 my $subfieldcode = $subfield->[0];
2466 # warn "INDEXING :".$subfield->[1];
2467 # check each index to see if the subfield is stored somewhere
2468 # otherwise, store it in __RAW__ index
2469 foreach my $key (keys %index) {
2470 # warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
2471 if ($index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/) {
2473 my $line= lc $subfield->[1];
2474 # remove meaningless value in the field...
2475 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:|\r|\n/ /g;
2476 # ... and split in words
2477 foreach (split / /,$line) {
2478 next unless $_; # skip empty values (multiple spaces)
2479 # if the entry is already here, improve weight
2480 # warn "managing $_";
2481 if ( exists $result{$key}->{$_} && $result{$key}->{"$_"} =~ /$biblionumber,\Q$title\E\-(\d+);/) {
2482 my $weight = $1 + 1;
2483 $result{$key}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//g;
2484 $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
2486 # get the value if it exist in the nozebra table, otherwise, create it
2487 $sth2->execute($server,$key,$_);
2488 my $existing_biblionumbers = $sth2->fetchrow;
2490 if ($existing_biblionumbers) {
2491 $result{$key}->{"$_"} =$existing_biblionumbers;
2492 my $weight = defined $1 ? $1 + 1 : 1;
2493 $result{$key}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//g;
2494 $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
2495 # create a new ligne for this entry
2497 # warn "INSERT : $server / $key / $_";
2498 $dbh->do('INSERT INTO nozebra SET server='.$dbh->quote($server).', indexname='.$dbh->quote($key).',value='.$dbh->quote($_));
2499 $result{$key}->{"$_"}.="$biblionumber,$title-1;";
2505 # the subfield is not indexed, store it in __RAW__ index anyway
2507 my $line= lc $subfield->[1];
2508 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:|\r|\n/ /g;
2509 # ... and split in words
2510 foreach (split / /,$line) {
2511 next unless $_; # skip empty values (multiple spaces)
2512 # if the entry is already here, improve weight
2513 if ($result{'__RAW__'}->{"$_"} =~ /$biblionumber,\Q$title\E\-(\d+);/) {
2515 $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//;
2516 $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
2518 # get the value if it exist in the nozebra table, otherwise, create it
2519 $sth2->execute($server,'__RAW__',$_);
2520 my $existing_biblionumbers = $sth2->fetchrow;
2522 if ($existing_biblionumbers) {
2523 $result{'__RAW__'}->{"$_"} =$existing_biblionumbers;
2525 $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//;
2526 $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
2527 # create a new ligne for this entry
2529 $dbh->do('INSERT INTO nozebra SET server='.$dbh->quote($server).', indexname="__RAW__",value='.$dbh->quote($_));
2530 $result{'__RAW__'}->{"$_"}.="$biblionumber,$title-1;";
2545 ($indicators, $value) = _find_value($tag, $subfield, $record,$encoding);
2547 Find the given $subfield in the given $tag in the given
2548 MARC::Record $record. If the subfield is found, returns
2549 the (indicators, value) pair; otherwise, (undef, undef) is
2553 Such a function is used in addbiblio AND additem and serial-edit and maybe could be used in Authorities.
2554 I suggest we export it from this module.
2561 my ( $tagfield, $insubfield, $record, $encoding ) = @_;
2564 if ( $tagfield < 10 ) {
2565 if ( $record->field($tagfield) ) {
2566 push @result, $record->field($tagfield)->data();
2573 foreach my $field ( $record->field($tagfield) ) {
2574 my @subfields = $field->subfields();
2575 foreach my $subfield (@subfields) {
2576 if ( @$subfield[0] eq $insubfield ) {
2577 push @result, @$subfield[1];
2578 $indicator = $field->indicator(1) . $field->indicator(2);
2583 return ( $indicator, @result );
2586 =head2 _koha_marc_update_bib_ids
2590 _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
2592 Internal function to add or update biblionumber and biblioitemnumber to
2599 sub _koha_marc_update_bib_ids {
2600 my ($record, $frameworkcode, $biblionumber, $biblioitemnumber) = @_;
2602 # we must add bibnum and bibitemnum in MARC::Record...
2603 # we build the new field with biblionumber and biblioitemnumber
2604 # we drop the original field
2605 # we add the new builded field.
2606 my ($biblio_tag, $biblio_subfield ) = GetMarcFromKohaField("biblio.biblionumber",$frameworkcode);
2607 my ($biblioitem_tag, $biblioitem_subfield ) = GetMarcFromKohaField("biblioitems.biblioitemnumber",$frameworkcode);
2609 if ($biblio_tag != $biblioitem_tag) {
2610 # biblionumber & biblioitemnumber are in different fields
2612 # deal with biblionumber
2613 my ($new_field, $old_field);
2614 if ($biblio_tag < 10) {
2615 $new_field = MARC::Field->new( $biblio_tag, $biblionumber );
2618 MARC::Field->new( $biblio_tag, '', '',
2619 "$biblio_subfield" => $biblionumber );
2622 # drop old field and create new one...
2623 $old_field = $record->field($biblio_tag);
2624 $record->delete_field($old_field) if $old_field;
2625 $record->append_fields($new_field);
2627 # deal with biblioitemnumber
2628 if ($biblioitem_tag < 10) {
2629 $new_field = MARC::Field->new( $biblioitem_tag, $biblioitemnumber, );
2632 MARC::Field->new( $biblioitem_tag, '', '',
2633 "$biblioitem_subfield" => $biblioitemnumber, );
2635 # drop old field and create new one...
2636 $old_field = $record->field($biblioitem_tag);
2637 $record->delete_field($old_field) if $old_field;
2638 $record->insert_fields_ordered($new_field);
2641 # biblionumber & biblioitemnumber are in the same field (can't be <10 as fields <10 have only 1 value)
2642 my $new_field = MARC::Field->new(
2643 $biblio_tag, '', '',
2644 "$biblio_subfield" => $biblionumber,
2645 "$biblioitem_subfield" => $biblioitemnumber
2648 # drop old field and create new one...
2649 my $old_field = $record->field($biblio_tag);
2650 $record->delete_field($old_field) if $old_field;
2651 $record->insert_fields_ordered($new_field);
2655 =head2 _koha_marc_update_biblioitem_cn_sort
2659 _koha_marc_update_biblioitem_cn_sort($marc, $biblioitem, $frameworkcode);
2663 Given a MARC bib record and the biblioitem hash, update the
2664 subfield that contains a copy of the value of biblioitems.cn_sort.
2668 sub _koha_marc_update_biblioitem_cn_sort {
2670 my $biblioitem = shift;
2671 my $frameworkcode= shift;
2673 my ($biblioitem_tag, $biblioitem_subfield ) = GetMarcFromKohaField("biblioitems.cn_sort",$frameworkcode);
2674 return unless $biblioitem_tag;
2676 my ($cn_sort) = GetClassSort($biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
2678 if (my $field = $marc->field($biblioitem_tag)) {
2679 $field->delete_subfield(code => $biblioitem_subfield);
2680 if ($cn_sort ne '') {
2681 $field->add_subfields($biblioitem_subfield => $cn_sort);
2684 # if we get here, no biblioitem tag is present in the MARC record, so
2685 # we'll create it if $cn_sort is not empty -- this would be
2686 # an odd combination of events, however
2688 $marc->insert_grouped_field(MARC::Field->new($biblioitem_tag, ' ', ' ', $biblioitem_subfield => $cn_sort));
2693 =head2 _koha_add_biblio
2697 my ($biblionumber,$error) = _koha_add_biblio($dbh,$biblioitem);
2699 Internal function to add a biblio ($biblio is a hash with the values)
2705 sub _koha_add_biblio {
2706 my ( $dbh, $biblio, $frameworkcode ) = @_;
2710 # set the series flag
2712 if ( $biblio->{'seriestitle'} ) { $serial = 1 };
2716 SET frameworkcode = ?,
2727 my $sth = $dbh->prepare($query);
2730 $biblio->{'author'},
2732 $biblio->{'unititle'},
2735 $biblio->{'seriestitle'},
2736 $biblio->{'copyrightdate'},
2737 $biblio->{'abstract'}
2740 my $biblionumber = $dbh->{'mysql_insertid'};
2741 if ( $dbh->errstr ) {
2742 $error.="ERROR in _koha_add_biblio $query".$dbh->errstr;
2747 #warn "LEAVING _koha_add_biblio: ".$biblionumber."\n";
2748 return ($biblionumber,$error);
2751 =head2 _koha_modify_biblio
2755 my ($biblionumber,$error) == _koha_modify_biblio($dbh,$biblio,$frameworkcode);
2757 Internal function for updating the biblio table
2763 sub _koha_modify_biblio {
2764 my ( $dbh, $biblio, $frameworkcode ) = @_;
2769 SET frameworkcode = ?,
2778 WHERE biblionumber = ?
2781 my $sth = $dbh->prepare($query);
2785 $biblio->{'author'},
2787 $biblio->{'unititle'},
2789 $biblio->{'serial'},
2790 $biblio->{'seriestitle'},
2791 $biblio->{'copyrightdate'},
2792 $biblio->{'abstract'},
2793 $biblio->{'biblionumber'}
2794 ) if $biblio->{'biblionumber'};
2796 if ( $dbh->errstr || !$biblio->{'biblionumber'} ) {
2797 $error.="ERROR in _koha_modify_biblio $query".$dbh->errstr;
2800 return ( $biblio->{'biblionumber'},$error );
2803 =head2 _koha_modify_biblioitem_nonmarc
2807 my ($biblioitemnumber,$error) = _koha_modify_biblioitem_nonmarc( $dbh, $biblioitem );
2809 Updates biblioitems row except for marc and marcxml, which should be changed
2816 sub _koha_modify_biblioitem_nonmarc {
2817 my ( $dbh, $biblioitem ) = @_;
2820 # re-calculate the cn_sort, it may have changed
2821 my ($cn_sort) = GetClassSort($biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
2825 SET biblionumber = ?,
2831 publicationyear = ?,
2835 collectiontitle = ?,
2837 collectionvolume= ?,
2838 editionstatement= ?,
2839 editionresponsibility = ?,
2853 where biblioitemnumber = ?
2855 my $sth = $dbh->prepare($query);
2857 $biblioitem->{'biblionumber'},
2858 $biblioitem->{'volume'},
2859 $biblioitem->{'number'},
2860 $biblioitem->{'itemtype'},
2861 $biblioitem->{'isbn'},
2862 $biblioitem->{'issn'},
2863 $biblioitem->{'publicationyear'},
2864 $biblioitem->{'publishercode'},
2865 $biblioitem->{'volumedate'},
2866 $biblioitem->{'volumedesc'},
2867 $biblioitem->{'collectiontitle'},
2868 $biblioitem->{'collectionissn'},
2869 $biblioitem->{'collectionvolume'},
2870 $biblioitem->{'editionstatement'},
2871 $biblioitem->{'editionresponsibility'},
2872 $biblioitem->{'illus'},
2873 $biblioitem->{'pages'},
2874 $biblioitem->{'bnotes'},
2875 $biblioitem->{'size'},
2876 $biblioitem->{'place'},
2877 $biblioitem->{'lccn'},
2878 $biblioitem->{'url'},
2879 $biblioitem->{'biblioitems.cn_source'},
2880 $biblioitem->{'cn_class'},
2881 $biblioitem->{'cn_item'},
2882 $biblioitem->{'cn_suffix'},
2884 $biblioitem->{'totalissues'},
2885 $biblioitem->{'biblioitemnumber'}
2887 if ( $dbh->errstr ) {
2888 $error.="ERROR in _koha_modify_biblioitem_nonmarc $query".$dbh->errstr;
2891 return ($biblioitem->{'biblioitemnumber'},$error);
2894 =head2 _koha_add_biblioitem
2898 my ($biblioitemnumber,$error) = _koha_add_biblioitem( $dbh, $biblioitem );
2900 Internal function to add a biblioitem
2906 sub _koha_add_biblioitem {
2907 my ( $dbh, $biblioitem ) = @_;
2910 my ($cn_sort) = GetClassSort($biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
2912 "INSERT INTO biblioitems SET
2919 publicationyear = ?,
2923 collectiontitle = ?,
2925 collectionvolume= ?,
2926 editionstatement= ?,
2927 editionresponsibility = ?,
2943 my $sth = $dbh->prepare($query);
2945 $biblioitem->{'biblionumber'},
2946 $biblioitem->{'volume'},
2947 $biblioitem->{'number'},
2948 $biblioitem->{'itemtype'},
2949 $biblioitem->{'isbn'},
2950 $biblioitem->{'issn'},
2951 $biblioitem->{'publicationyear'},
2952 $biblioitem->{'publishercode'},
2953 $biblioitem->{'volumedate'},
2954 $biblioitem->{'volumedesc'},
2955 $biblioitem->{'collectiontitle'},
2956 $biblioitem->{'collectionissn'},
2957 $biblioitem->{'collectionvolume'},
2958 $biblioitem->{'editionstatement'},
2959 $biblioitem->{'editionresponsibility'},
2960 $biblioitem->{'illus'},
2961 $biblioitem->{'pages'},
2962 $biblioitem->{'bnotes'},
2963 $biblioitem->{'size'},
2964 $biblioitem->{'place'},
2965 $biblioitem->{'lccn'},
2966 $biblioitem->{'marc'},
2967 $biblioitem->{'url'},
2968 $biblioitem->{'biblioitems.cn_source'},
2969 $biblioitem->{'cn_class'},
2970 $biblioitem->{'cn_item'},
2971 $biblioitem->{'cn_suffix'},
2973 $biblioitem->{'totalissues'}
2975 my $bibitemnum = $dbh->{'mysql_insertid'};
2976 if ( $dbh->errstr ) {
2977 $error.="ERROR in _koha_add_biblioitem $query".$dbh->errstr;
2981 return ($bibitemnum,$error);
2984 =head2 _koha_delete_biblio
2988 $error = _koha_delete_biblio($dbh,$biblionumber);
2990 Internal sub for deleting from biblio table -- also saves to deletedbiblio
2992 C<$dbh> - the database handle
2993 C<$biblionumber> - the biblionumber of the biblio to be deleted
2999 # FIXME: add error handling
3001 sub _koha_delete_biblio {
3002 my ( $dbh, $biblionumber ) = @_;
3004 # get all the data for this biblio
3005 my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber=?");
3006 $sth->execute($biblionumber);
3008 if ( my $data = $sth->fetchrow_hashref ) {
3010 # save the record in deletedbiblio
3011 # find the fields to save
3012 my $query = "INSERT INTO deletedbiblio SET ";
3014 foreach my $temp ( keys %$data ) {
3015 $query .= "$temp = ?,";
3016 push( @bind, $data->{$temp} );
3019 # replace the last , by ",?)"
3021 my $bkup_sth = $dbh->prepare($query);
3022 $bkup_sth->execute(@bind);
3026 my $del_sth = $dbh->prepare("DELETE FROM biblio WHERE biblionumber=?");
3027 $del_sth->execute($biblionumber);
3034 =head2 _koha_delete_biblioitems
3038 $error = _koha_delete_biblioitems($dbh,$biblioitemnumber);
3040 Internal sub for deleting from biblioitems table -- also saves to deletedbiblioitems
3042 C<$dbh> - the database handle
3043 C<$biblionumber> - the biblioitemnumber of the biblioitem to be deleted
3049 # FIXME: add error handling
3051 sub _koha_delete_biblioitems {
3052 my ( $dbh, $biblioitemnumber ) = @_;
3054 # get all the data for this biblioitem
3056 $dbh->prepare("SELECT * FROM biblioitems WHERE biblioitemnumber=?");
3057 $sth->execute($biblioitemnumber);
3059 if ( my $data = $sth->fetchrow_hashref ) {
3061 # save the record in deletedbiblioitems
3062 # find the fields to save
3063 my $query = "INSERT INTO deletedbiblioitems SET ";
3065 foreach my $temp ( keys %$data ) {
3066 $query .= "$temp = ?,";
3067 push( @bind, $data->{$temp} );
3070 # replace the last , by ",?)"
3072 my $bkup_sth = $dbh->prepare($query);
3073 $bkup_sth->execute(@bind);
3076 # delete the biblioitem
3078 $dbh->prepare("DELETE FROM biblioitems WHERE biblioitemnumber=?");
3079 $del_sth->execute($biblioitemnumber);
3086 =head1 UNEXPORTED FUNCTIONS
3088 =head2 ModBiblioMarc
3090 &ModBiblioMarc($newrec,$biblionumber,$frameworkcode);
3092 Add MARC data for a biblio to koha
3094 Function exported, but should NOT be used, unless you really know what you're doing
3100 # pass the MARC::Record to this function, and it will create the records in the marc field
3101 my ( $record, $biblionumber, $frameworkcode ) = @_;
3102 my $dbh = C4::Context->dbh;
3103 my @fields = $record->fields();
3104 if ( !$frameworkcode ) {
3105 $frameworkcode = "";
3108 $dbh->prepare("UPDATE biblio SET frameworkcode=? WHERE biblionumber=?");
3109 $sth->execute( $frameworkcode, $biblionumber );
3111 my $encoding = C4::Context->preference("marcflavour");
3113 # deal with UNIMARC field 100 (encoding) : create it if needed & set encoding to unicode
3114 if ( $encoding eq "UNIMARC" ) {
3116 if ( length($record->subfield( 100, "a" )) == 35 ) {
3117 $string = $record->subfield( 100, "a" );
3118 my $f100 = $record->field(100);
3119 $record->delete_field($f100);
3122 $string = POSIX::strftime( "%Y%m%d", localtime );
3124 $string = sprintf( "%-*s", 35, $string );
3126 substr( $string, 22, 6, "frey50" );
3127 unless ( $record->subfield( 100, "a" ) ) {
3128 $record->insert_grouped_field(
3129 MARC::Field->new( 100, "", "", "a" => $string ) );
3133 if (C4::Context->preference("NoZebra")) {
3134 # only NoZebra indexing needs to have
3135 # the previous version of the record
3136 $oldRecord = GetMarcBiblio($biblionumber);
3140 "UPDATE biblioitems SET marc=?,marcxml=? WHERE biblionumber=?");
3141 $sth->execute( $record->as_usmarc(), $record->as_xml_record($encoding),
3144 ModZebra($biblionumber,"specialUpdate","biblioserver",$oldRecord,$record);
3145 return $biblionumber;
3148 =head2 z3950_extended_services
3150 z3950_extended_services($serviceType,$serviceOptions,$record);
3152 z3950_extended_services is used to handle all interactions with Zebra's extended serices package, which is employed to perform all management of the MARC data stored in Zebra.
3154 C<$serviceType> one of: itemorder,create,drop,commit,update,xmlupdate
3156 C<$serviceOptions> a has of key/value pairs. For instance, if service_type is 'update', $service_options should contain:
3158 action => update action, one of specialUpdate, recordInsert, recordReplace, recordDelete, elementUpdate.
3162 recordidOpaque => Opaque Record ID (user supplied) or recordidNumber => Record ID number (system number).
3163 syntax => the record syntax (transfer syntax)
3164 databaseName = Database from connection object
3166 To set serviceOptions, call set_service_options($serviceType)
3168 C<$record> the record, if one is needed for the service type
3170 A record should be in XML. You can convert it to XML from MARC by running it through marc2xml().
3174 sub z3950_extended_services {
3175 my ( $server, $serviceType, $action, $serviceOptions ) = @_;
3177 # get our connection object
3178 my $Zconn = C4::Context->Zconn( $server, 0, 1 );
3180 # create a new package object
3181 my $Zpackage = $Zconn->package();
3184 $Zpackage->option( action => $action );
3186 if ( $serviceOptions->{'databaseName'} ) {
3187 $Zpackage->option( databaseName => $serviceOptions->{'databaseName'} );
3189 if ( $serviceOptions->{'recordIdNumber'} ) {
3191 recordIdNumber => $serviceOptions->{'recordIdNumber'} );
3193 if ( $serviceOptions->{'recordIdOpaque'} ) {
3195 recordIdOpaque => $serviceOptions->{'recordIdOpaque'} );
3198 # this is an ILL request (Zebra doesn't support it, but Koha could eventually)
3199 #if ($serviceType eq 'itemorder') {
3200 # $Zpackage->option('contact-name' => $serviceOptions->{'contact-name'});
3201 # $Zpackage->option('contact-phone' => $serviceOptions->{'contact-phone'});
3202 # $Zpackage->option('contact-email' => $serviceOptions->{'contact-email'});
3203 # $Zpackage->option('itemorder-item' => $serviceOptions->{'itemorder-item'});
3206 if ( $serviceOptions->{record} ) {
3207 $Zpackage->option( record => $serviceOptions->{record} );
3209 # can be xml or marc
3210 if ( $serviceOptions->{'syntax'} ) {
3211 $Zpackage->option( syntax => $serviceOptions->{'syntax'} );
3215 # send the request, handle any exception encountered
3216 eval { $Zpackage->send($serviceType) };
3217 if ( $@ && $@->isa("ZOOM::Exception") ) {
3218 return "error: " . $@->code() . " " . $@->message() . "\n";
3221 # free up package resources
3222 $Zpackage->destroy();
3225 =head2 set_service_options
3227 my $serviceOptions = set_service_options($serviceType);
3229 C<$serviceType> itemorder,create,drop,commit,update,xmlupdate
3231 Currently, we only support 'create', 'commit', and 'update'. 'drop' support will be added as soon as Zebra supports it.
3235 sub set_service_options {
3236 my ($serviceType) = @_;
3239 # FIXME: This needs to be an OID ... if we ever need 'syntax' this sub will need to change
3240 # $serviceOptions->{ 'syntax' } = ''; #zebra doesn't support syntaxes other than xml
3242 if ( $serviceType eq 'commit' ) {
3246 if ( $serviceType eq 'create' ) {
3250 if ( $serviceType eq 'drop' ) {
3251 die "ERROR: 'drop' not currently supported (by Zebra)";
3253 return $serviceOptions;
3256 =head3 get_biblio_authorised_values
3258 find the types and values for all authorised values assigned to this biblio.
3263 returns: a hashref malling the authorised value to the value set for this biblionumber
3265 $authorised_values = {
3266 'Scent' => 'flowery',
3267 'Audience' => 'Young Adult',
3268 'itemtypes' => 'SER',
3271 Notes: forlibrarian should probably be passed in, and called something different.
3276 sub get_biblio_authorised_values {
3277 my $biblionumber = shift;
3279 my $forlibrarian = 1; # are we in staff or opac?
3280 my $frameworkcode = GetFrameworkCode( $biblionumber );
3282 my $authorised_values;
3284 my $record = GetMarcBiblio( $biblionumber )
3285 or return $authorised_values;
3286 my $tagslib = GetMarcStructure( $forlibrarian, $frameworkcode )
3287 or return $authorised_values;
3289 # assume that these entries in the authorised_value table are bibliolevel.
3290 # ones that start with 'item%' are item level.
3291 my $query = q(SELECT distinct authorised_value, kohafield
3292 FROM marc_subfield_structure
3293 WHERE authorised_value !=''
3294 AND (kohafield like 'biblio%'
3295 OR kohafield like '') );
3296 my $bibliolevel_authorised_values = C4::Context->dbh->selectall_hashref( $query, 'authorised_value' );
3298 foreach my $tag ( keys( %$tagslib ) ) {
3299 foreach my $subfield ( keys( %{$tagslib->{ $tag }} ) ) {
3300 # warn "checking $subfield. type is: " . ref $tagslib->{ $tag }{ $subfield };
3301 if ( 'HASH' eq ref $tagslib->{ $tag }{ $subfield } ) {
3302 if ( defined $tagslib->{ $tag }{ $subfield }{'authorised_value'} && exists $bibliolevel_authorised_values->{ $tagslib->{ $tag }{ $subfield }{'authorised_value'} } ) {
3303 if ( defined $record->field( $tag ) ) {
3304 my $this_subfield_value = $record->field( $tag )->subfield( $subfield );
3305 if ( defined $this_subfield_value ) {
3306 $authorised_values->{ $tagslib->{ $tag }{ $subfield }{'authorised_value'} } = $this_subfield_value;
3313 # warn ( Data::Dumper->Dump( [ $authorised_values ], [ 'authorised_values' ] ) );
3314 return $authorised_values;
3324 Koha Developement team <info@koha.org>
3326 Paul POULAIN paul.poulain@free.fr
3328 Joshua Ferraro jmf@liblime.com