3 # Copyright 2000-2002 Katipo Communications
4 # Copyright 2010 BibLibre
5 # Copyright 2011 Equinox Software, Inc.
7 # This file is part of Koha.
9 # Koha is free software; you can redistribute it and/or modify it under the
10 # terms of the GNU General Public License as published by the Free Software
11 # Foundation; either version 2 of the License, or (at your option) any later
14 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License along
19 # with Koha; if not, write to the Free Software Foundation, Inc.,
20 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 use MARC
::File
::USMARC
;
30 use POSIX
qw(strftime);
33 use C4
::Dates qw
/format_date/;
34 use C4
::Log
; # logaction
39 use vars
qw($VERSION @ISA @EXPORT);
45 @ISA = qw( Exporter );
60 &GetBiblioItemByBiblioNumber
61 &GetBiblioFromItemNumber
62 &GetBiblionumberFromItemnumber
87 &GetAuthorisedValueDesc
100 # To modify something
107 # To delete something
112 # To link headings in a bib record
113 # to authority records.
116 &LinkBibHeadingsToAuthorities
120 # those functions are exported but should not be used
121 # they are usefull is few circumstances, so are exported.
122 # but don't use them unless you're a core developer ;-)
130 &TransformHtmlToMarc2
138 if (C4
::Context
->ismemcached) {
139 require Memoize
::Memcached
;
140 import Memoize
::Memcached
qw(memoize_memcached);
142 memoize_memcached
( 'GetMarcStructure',
143 memcached
=> C4
::Context
->memcached);
149 C4::Biblio - cataloging management functions
153 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:
157 =item 1. in the biblio,biblioitems,items, etc tables, which are limited to a one-to-one mapping to underlying MARC data
159 =item 2. as raw MARC in the Zebra index and storage engine
161 =item 3. as raw MARC the biblioitems.marc and biblioitems.marcxml
165 In the 3.0 version of Koha, the authoritative record-level information is in biblioitems.marcxml
167 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.
171 =item 1. Compared with MySQL, Zebra is slow to update an index for small data changes -- especially for proc-intensive operations like circulation
173 =item 2. Zebra's index has been known to crash and a backup of the data is necessary to rebuild it in such cases
177 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:
181 =item 1. Add*/Mod*/Del*/ - high-level external functions suitable for being called from external scripts to manage the collection
183 =item 2. _koha_* - low-level internal functions for managing the koha tables
185 =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.
187 =item 4. Zebra functions used to update the Zebra index
189 =item 5. internal helper functions such as char_decode, checkitems, etc. Some of these probably belong in Koha.pm
193 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 :
197 =item 1. save datas in biblio and biblioitems table, that gives us a biblionumber and a biblioitemnumber
199 =item 2. add the biblionumber and biblioitemnumber into the MARC records
201 =item 3. save the marc record
205 When dealing with items, we must :
209 =item 1. save the item in items table, that gives us an itemnumber
211 =item 2. add the itemnumber to the item MARC field
213 =item 3. overwrite the MARC record (with the added item) into biblioitems.marc(xml)
215 When modifying a biblio or an item, the behaviour is quite similar.
219 =head1 EXPORTED FUNCTIONS
223 ($biblionumber,$biblioitemnumber) = AddBiblio($record,$frameworkcode);
225 Exported function (core API) for adding a new biblio to koha.
227 The first argument is a C<MARC::Record> object containing the
228 bib to add, while the second argument is the desired MARC
231 This function also accepts a third, optional argument: a hashref
232 to additional options. The only defined option is C<defer_marc_save>,
233 which if present and mapped to a true value, causes C<AddBiblio>
234 to omit the call to save the MARC in C<bibilioitems.marc>
235 and C<biblioitems.marcxml> This option is provided B<only>
236 for the use of scripts such as C<bulkmarcimport.pl> that may need
237 to do some manipulation of the MARC record for item parsing before
238 saving it and which cannot afford the performance hit of saving
239 the MARC record twice. Consequently, do not use that option
240 unless you can guarantee that C<ModBiblioMarc> will be called.
246 my $frameworkcode = shift;
247 my $options = @_ ?
shift : undef;
248 my $defer_marc_save = 0;
249 if ( defined $options and exists $options->{'defer_marc_save'} and $options->{'defer_marc_save'} ) {
250 $defer_marc_save = 1;
253 my ( $biblionumber, $biblioitemnumber, $error );
254 my $dbh = C4
::Context
->dbh;
256 # transform the data into koha-table style data
257 SetUTF8Flag
($record);
258 my $olddata = TransformMarcToKoha
( $dbh, $record, $frameworkcode );
259 ( $biblionumber, $error ) = _koha_add_biblio
( $dbh, $olddata, $frameworkcode );
260 $olddata->{'biblionumber'} = $biblionumber;
261 ( $biblioitemnumber, $error ) = _koha_add_biblioitem
( $dbh, $olddata );
263 _koha_marc_update_bib_ids
( $record, $frameworkcode, $biblionumber, $biblioitemnumber );
265 # update MARC subfield that stores biblioitems.cn_sort
266 _koha_marc_update_biblioitem_cn_sort
( $record, $olddata, $frameworkcode );
269 ModBiblioMarc
( $record, $biblionumber, $frameworkcode ) unless $defer_marc_save;
271 logaction
( "CATALOGUING", "ADD", $biblionumber, "biblio" ) if C4
::Context
->preference("CataloguingLog");
272 return ( $biblionumber, $biblioitemnumber );
277 ModBiblio( $record,$biblionumber,$frameworkcode);
279 Replace an existing bib record identified by C<$biblionumber>
280 with one supplied by the MARC::Record object C<$record>. The embedded
281 item, biblioitem, and biblionumber fields from the previous
282 version of the bib record replace any such fields of those tags that
283 are present in C<$record>. Consequently, ModBiblio() is not
284 to be used to try to modify item records.
286 C<$frameworkcode> specifies the MARC framework to use
287 when storing the modified bib record; among other things,
288 this controls how MARC fields get mapped to display columns
289 in the C<biblio> and C<biblioitems> tables, as well as
290 which fields are used to store embedded item, biblioitem,
291 and biblionumber data for indexing.
296 my ( $record, $biblionumber, $frameworkcode ) = @_;
297 croak
"No record" unless $record;
299 if ( C4
::Context
->preference("CataloguingLog") ) {
300 my $newrecord = GetMarcBiblio
($biblionumber);
301 logaction
( "CATALOGUING", "MODIFY", $biblionumber, "BEFORE=>" . $newrecord->as_formatted );
304 # Cleaning up invalid fields must be done early or SetUTF8Flag is liable to
305 # throw an exception which probably won't be handled.
306 foreach my $field ($record->fields()) {
307 if (! $field->is_control_field()) {
308 if (scalar($field->subfields()) == 0 || (scalar($field->subfields()) == 1 && $field->subfield('9'))) {
309 $record->delete_field($field);
314 SetUTF8Flag
($record);
315 my $dbh = C4
::Context
->dbh;
317 $frameworkcode = "" if !$frameworkcode || $frameworkcode eq "Default"; # XXX
319 _strip_item_fields
($record, $frameworkcode);
321 # update biblionumber and biblioitemnumber in MARC
322 # FIXME - this is assuming a 1 to 1 relationship between
323 # biblios and biblioitems
324 my $sth = $dbh->prepare("select biblioitemnumber from biblioitems where biblionumber=?");
325 $sth->execute($biblionumber);
326 my ($biblioitemnumber) = $sth->fetchrow;
328 _koha_marc_update_bib_ids
( $record, $frameworkcode, $biblionumber, $biblioitemnumber );
330 # load the koha-table data object
331 my $oldbiblio = TransformMarcToKoha
( $dbh, $record, $frameworkcode );
333 # update MARC subfield that stores biblioitems.cn_sort
334 _koha_marc_update_biblioitem_cn_sort
( $record, $oldbiblio, $frameworkcode );
336 # update the MARC record (that now contains biblio and items) with the new record data
337 &ModBiblioMarc
( $record, $biblionumber, $frameworkcode );
339 # modify the other koha tables
340 _koha_modify_biblio
( $dbh, $oldbiblio, $frameworkcode );
341 _koha_modify_biblioitem_nonmarc
( $dbh, $oldbiblio );
345 =head2 _strip_item_fields
347 _strip_item_fields($record, $frameworkcode)
349 Utility routine to remove item tags from a
354 sub _strip_item_fields
{
356 my $frameworkcode = shift;
357 # get the items before and append them to the biblio before updating the record, atm we just have the biblio
358 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField
( "items.itemnumber", $frameworkcode );
360 # delete any item fields from incoming record to avoid
361 # duplication or incorrect data - use AddItem() or ModItem()
363 foreach my $field ( $record->field($itemtag) ) {
364 $record->delete_field($field);
368 =head2 ModBiblioframework
370 ModBiblioframework($biblionumber,$frameworkcode);
372 Exported function to modify a biblio framework
376 sub ModBiblioframework
{
377 my ( $biblionumber, $frameworkcode ) = @_;
378 my $dbh = C4
::Context
->dbh;
379 my $sth = $dbh->prepare( "UPDATE biblio SET frameworkcode=? WHERE biblionumber=?" );
380 $sth->execute( $frameworkcode, $biblionumber );
386 my $error = &DelBiblio($biblionumber);
388 Exported function (core API) for deleting a biblio in koha.
389 Deletes biblio record from Zebra and Koha tables (biblio,biblioitems,items)
390 Also backs it up to deleted* tables
391 Checks to make sure there are not issues on any of the items
393 C<$error> : undef unless an error occurs
398 my ($biblionumber) = @_;
399 my $dbh = C4
::Context
->dbh;
400 my $error; # for error handling
402 # First make sure this biblio has no items attached
403 my $sth = $dbh->prepare("SELECT itemnumber FROM items WHERE biblionumber=?");
404 $sth->execute($biblionumber);
405 if ( my $itemnumber = $sth->fetchrow ) {
407 # Fix this to use a status the template can understand
408 $error .= "This Biblio has items attached, please delete them first before deleting this biblio ";
411 return $error if $error;
413 # We delete attached subscriptions
415 my $subscriptions = C4
::Serials
::GetFullSubscriptionsFromBiblionumber
($biblionumber);
416 foreach my $subscription (@
$subscriptions) {
417 C4
::Serials
::DelSubscription
( $subscription->{subscriptionid
} );
420 # Delete in Zebra. Be careful NOT to move this line after _koha_delete_biblio
421 # for at least 2 reasons :
422 # - we need to read the biblio if NoZebra is set (to remove it from the indexes
423 # - if something goes wrong, the biblio may be deleted from Koha but not from zebra
424 # 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)
426 if ( C4
::Context
->preference("NoZebra") ) {
428 # only NoZebra indexing needs to have
429 # the previous version of the record
430 $oldRecord = GetMarcBiblio
($biblionumber);
432 ModZebra
( $biblionumber, "recordDelete", "biblioserver", $oldRecord, undef );
434 # delete biblioitems and items from Koha tables and save in deletedbiblioitems,deleteditems
435 $sth = $dbh->prepare("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
436 $sth->execute($biblionumber);
437 while ( my $biblioitemnumber = $sth->fetchrow ) {
439 # delete this biblioitem
440 $error = _koha_delete_biblioitems
( $dbh, $biblioitemnumber );
441 return $error if $error;
444 # delete biblio from Koha tables and save in deletedbiblio
445 # must do this *after* _koha_delete_biblioitems, otherwise
446 # delete cascade will prevent deletedbiblioitems rows
447 # from being generated by _koha_delete_biblioitems
448 $error = _koha_delete_biblio
( $dbh, $biblionumber );
450 logaction
( "CATALOGUING", "DELETE", $biblionumber, "" ) if C4
::Context
->preference("CataloguingLog");
456 =head2 BiblioAutoLink
458 my $headings_linked = BiblioAutoLink($record, $frameworkcode)
460 Automatically links headings in a bib record to authorities.
466 my $frameworkcode = shift;
467 my ( $num_headings_changed, %results );
470 "C4::Linker::" . ( C4
::Context
->preference("LinkerModule") || 'Default' );
471 eval { eval "require $linker_module"; };
473 $linker_module = 'C4::Linker::Default';
474 eval "require $linker_module";
480 my $linker = $linker_module->new(
481 { 'options' => C4
::Context
->preference("LinkerOptions") } );
482 my ( $headings_changed, undef ) =
483 LinkBibHeadingsToAuthorities
( $linker, $record, $frameworkcode, C4
::Context
->preference("CatalogModuleRelink") || '' );
484 # By default we probably don't want to relink things when cataloging
485 return $headings_changed;
488 =head2 LinkBibHeadingsToAuthorities
490 my $num_headings_changed, %results = LinkBibHeadingsToAuthorities($linker, $marc, $frameworkcode, [$allowrelink]);
492 Links bib headings to authority records by checking
493 each authority-controlled field in the C<MARC::Record>
494 object C<$marc>, looking for a matching authority record,
495 and setting the linking subfield $9 to the ID of that
498 If $allowrelink is false, existing authids will never be
499 replaced, regardless of the values of LinkerKeepStale and
502 Returns the number of heading links changed in the
507 sub LinkBibHeadingsToAuthorities
{
510 my $frameworkcode = shift;
511 my $allowrelink = shift;
514 require C4
::AuthoritiesMarc
;
516 $allowrelink = 1 unless defined $allowrelink;
517 my $num_headings_changed = 0;
518 foreach my $field ( $bib->fields() ) {
519 my $heading = C4
::Heading
->new_from_bib_field( $field, $frameworkcode );
520 next unless defined $heading;
523 my $current_link = $field->subfield('9');
525 if ( defined $current_link && (!$allowrelink || !C4
::Context
->preference('LinkerRelink')) )
527 $results{'linked'}->{ $heading->display_form() }++;
531 my ( $authid, $fuzzy ) = $linker->get_link($heading);
533 $results{ $fuzzy ?
'fuzzy' : 'linked' }
534 ->{ $heading->display_form() }++;
535 next if defined $current_link and $current_link == $authid;
537 $field->delete_subfield( code
=> '9' ) if defined $current_link;
538 $field->add_subfields( '9', $authid );
539 $num_headings_changed++;
542 if ( defined $current_link
543 && (!$allowrelink || C4
::Context
->preference('LinkerKeepStale')) )
545 $results{'fuzzy'}->{ $heading->display_form() }++;
547 elsif ( C4
::Context
->preference('AutoCreateAuthorities') ) {
549 C4
::AuthoritiesMarc
::GetAuthType
( $heading->auth_type() );
550 my $marcrecordauth = MARC
::Record
->new();
551 if ( C4
::Context
->preference('marcflavour') eq 'MARC21' ) {
552 $marcrecordauth->leader(' nz a22 o 4500');
553 SetMarcUnicodeFlag
( $marcrecordauth, 'MARC21' );
556 MARC
::Field
->new( $authtypedata->{auth_tag_to_report
},
557 '', '', "a" => "" . $field->subfield('a') );
559 $authfield->add_subfields( $_->[0] => $_->[1] )
560 if ( $_->[0] =~ /[A-z]/ && $_->[0] ne "a" )
561 } $field->subfields();
562 $marcrecordauth->insert_fields_ordered($authfield);
564 # bug 2317: ensure new authority knows it's using UTF-8; currently
565 # only need to do this for MARC21, as MARC::Record->as_xml_record() handles
566 # automatically for UNIMARC (by not transcoding)
567 # FIXME: AddAuthority() instead should simply explicitly require that the MARC::Record
568 # use UTF-8, but as of 2008-08-05, did not want to introduce that kind
569 # of change to a core API just before the 3.0 release.
571 if ( C4
::Context
->preference('marcflavour') eq 'MARC21' ) {
572 $marcrecordauth->insert_fields_ordered(
575 'a' => "Machine generated authority record."
579 $bib->author() . ", "
580 . $bib->title_proper() . ", "
581 . $bib->publication_date() . " ";
582 $cite =~ s/^[\s\,]*//;
583 $cite =~ s/[\s\,]*$//;
586 . C4
::Context
->preference('MARCOrgCode') . ")"
587 . $bib->subfield( '999', 'c' ) . ": "
589 $marcrecordauth->insert_fields_ordered(
590 MARC
::Field
->new( '670', '', '', 'a' => $cite ) );
593 # warn "AUTH RECORD ADDED : ".$marcrecordauth->as_formatted;
596 C4
::AuthoritiesMarc
::AddAuthority
( $marcrecordauth, '',
597 $heading->auth_type() );
598 $field->add_subfields( '9', $authid );
599 $num_headings_changed++;
600 $results{'added'}->{ $heading->display_form() }++;
602 elsif ( defined $current_link ) {
603 $field->delete_subfield( code
=> '9' );
604 $num_headings_changed++;
605 $results{'unlinked'}->{ $heading->display_form() }++;
608 $results{'unlinked'}->{ $heading->display_form() }++;
613 return $num_headings_changed, \
%results;
616 =head2 GetRecordValue
618 my $values = GetRecordValue($field, $record, $frameworkcode);
620 Get MARC fields from a keyword defined in fieldmapping table.
625 my ( $field, $record, $frameworkcode ) = @_;
626 my $dbh = C4
::Context
->dbh;
628 my $sth = $dbh->prepare('SELECT fieldcode, subfieldcode FROM fieldmapping WHERE frameworkcode = ? AND field = ?');
629 $sth->execute( $frameworkcode, $field );
633 while ( my $row = $sth->fetchrow_hashref ) {
634 foreach my $field ( $record->field( $row->{fieldcode
} ) ) {
635 if ( ( $row->{subfieldcode
} ne "" && $field->subfield( $row->{subfieldcode
} ) ) ) {
636 foreach my $subfield ( $field->subfield( $row->{subfieldcode
} ) ) {
637 push @result, { 'subfield' => $subfield };
640 } elsif ( $row->{subfieldcode
} eq "" ) {
641 push @result, { 'subfield' => $field->as_string() };
649 =head2 SetFieldMapping
651 SetFieldMapping($framework, $field, $fieldcode, $subfieldcode);
653 Set a Field to MARC mapping value, if it already exists we don't add a new one.
657 sub SetFieldMapping
{
658 my ( $framework, $field, $fieldcode, $subfieldcode ) = @_;
659 my $dbh = C4
::Context
->dbh;
661 my $sth = $dbh->prepare('SELECT * FROM fieldmapping WHERE fieldcode = ? AND subfieldcode = ? AND frameworkcode = ? AND field = ?');
662 $sth->execute( $fieldcode, $subfieldcode, $framework, $field );
663 if ( not $sth->fetchrow_hashref ) {
665 $sth = $dbh->prepare('INSERT INTO fieldmapping (fieldcode, subfieldcode, frameworkcode, field) VALUES(?,?,?,?)');
667 $sth->execute( $fieldcode, $subfieldcode, $framework, $field );
671 =head2 DeleteFieldMapping
673 DeleteFieldMapping($id);
675 Delete a field mapping from an $id.
679 sub DeleteFieldMapping
{
681 my $dbh = C4
::Context
->dbh;
683 my $sth = $dbh->prepare('DELETE FROM fieldmapping WHERE id = ?');
687 =head2 GetFieldMapping
689 GetFieldMapping($frameworkcode);
691 Get all field mappings for a specified frameworkcode
695 sub GetFieldMapping
{
696 my ($framework) = @_;
697 my $dbh = C4
::Context
->dbh;
699 my $sth = $dbh->prepare('SELECT * FROM fieldmapping where frameworkcode = ?');
700 $sth->execute($framework);
703 while ( my $row = $sth->fetchrow_hashref ) {
711 $data = &GetBiblioData($biblionumber);
713 Returns information about the book with the given biblionumber.
714 C<&GetBiblioData> returns a reference-to-hash. The keys are the fields in
715 the C<biblio> and C<biblioitems> tables in the
718 In addition, C<$data-E<gt>{subject}> is the list of the book's
719 subjects, separated by C<" , "> (space, comma, space).
720 If there are multiple biblioitems with the given biblionumber, only
721 the first one is considered.
727 my $dbh = C4
::Context
->dbh;
729 # my $query = C4::Context->preference('item-level_itypes') ?
730 # " SELECT * , biblioitems.notes AS bnotes, biblio.notes
732 # LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
733 # WHERE biblio.biblionumber = ?
734 # AND biblioitems.biblionumber = biblio.biblionumber
737 my $query = " SELECT * , biblioitems.notes AS bnotes, itemtypes.notforloan as bi_notforloan, biblio.notes
739 LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
740 LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
741 WHERE biblio.biblionumber = ?
742 AND biblioitems.biblionumber = biblio.biblionumber ";
744 my $sth = $dbh->prepare($query);
745 $sth->execute($bibnum);
747 $data = $sth->fetchrow_hashref;
751 } # sub GetBiblioData
753 =head2 &GetBiblioItemData
755 $itemdata = &GetBiblioItemData($biblioitemnumber);
757 Looks up the biblioitem with the given biblioitemnumber. Returns a
758 reference-to-hash. The keys are the fields from the C<biblio>,
759 C<biblioitems>, and C<itemtypes> tables in the Koha database, except
760 that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
765 sub GetBiblioItemData
{
766 my ($biblioitemnumber) = @_;
767 my $dbh = C4
::Context
->dbh;
768 my $query = "SELECT *,biblioitems.notes AS bnotes
769 FROM biblio LEFT JOIN biblioitems on biblio.biblionumber=biblioitems.biblionumber ";
770 unless ( C4
::Context
->preference('item-level_itypes') ) {
771 $query .= "LEFT JOIN itemtypes on biblioitems.itemtype=itemtypes.itemtype ";
773 $query .= " WHERE biblioitemnumber = ? ";
774 my $sth = $dbh->prepare($query);
776 $sth->execute($biblioitemnumber);
777 $data = $sth->fetchrow_hashref;
780 } # sub &GetBiblioItemData
782 =head2 GetBiblioItemByBiblioNumber
784 NOTE : This function has been copy/paste from C4/Biblio.pm from head before zebra integration.
788 sub GetBiblioItemByBiblioNumber
{
789 my ($biblionumber) = @_;
790 my $dbh = C4
::Context
->dbh;
791 my $sth = $dbh->prepare("Select * FROM biblioitems WHERE biblionumber = ?");
795 $sth->execute($biblionumber);
797 while ( my $data = $sth->fetchrow_hashref ) {
798 push @results, $data;
805 =head2 GetBiblionumberFromItemnumber
810 sub GetBiblionumberFromItemnumber
{
811 my ($itemnumber) = @_;
812 my $dbh = C4
::Context
->dbh;
813 my $sth = $dbh->prepare("Select biblionumber FROM items WHERE itemnumber = ?");
815 $sth->execute($itemnumber);
816 my ($result) = $sth->fetchrow;
820 =head2 GetBiblioFromItemNumber
822 $item = &GetBiblioFromItemNumber($itemnumber,$barcode);
824 Looks up the item with the given itemnumber. if undef, try the barcode.
826 C<&itemnodata> returns a reference-to-hash whose keys are the fields
827 from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
833 sub GetBiblioFromItemNumber
{
834 my ( $itemnumber, $barcode ) = @_;
835 my $dbh = C4
::Context
->dbh;
838 $sth = $dbh->prepare(
840 LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
841 LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
842 WHERE items.itemnumber = ?"
844 $sth->execute($itemnumber);
846 $sth = $dbh->prepare(
848 LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
849 LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
850 WHERE items.barcode = ?"
852 $sth->execute($barcode);
854 my $data = $sth->fetchrow_hashref;
861 $isbd = &GetISBDView($biblionumber);
863 Return the ISBD view which can be included in opac and intranet
868 my ( $biblionumber, $template ) = @_;
869 my $record = GetMarcBiblio
($biblionumber, 1);
870 return undef unless defined $record;
871 my $itemtype = &GetFrameworkCode
($biblionumber);
872 my ( $holdingbrtagf, $holdingbrtagsubf ) = &GetMarcFromKohaField
( "items.holdingbranch", $itemtype );
873 my $tagslib = &GetMarcStructure
( 1, $itemtype );
875 my $ISBD = C4
::Context
->preference('isbd');
880 foreach my $isbdfield ( split( /#/, $bloc ) ) {
882 # $isbdfield= /(.?.?.?)/;
883 $isbdfield =~ /(\d\d\d)([^\|])?\|(.*)\|(.*)\|(.*)/;
884 my $fieldvalue = $1 || 0;
885 my $subfvalue = $2 || "";
887 my $analysestring = $4;
890 # warn "==> $1 / $2 / $3 / $4";
891 # my $fieldvalue=substr($isbdfield,0,3);
892 if ( $fieldvalue > 0 ) {
893 my $hasputtextbefore = 0;
894 my @fieldslist = $record->field($fieldvalue);
895 @fieldslist = sort { $a->subfield($holdingbrtagsubf) cmp $b->subfield($holdingbrtagsubf) } @fieldslist if ( $fieldvalue eq $holdingbrtagf );
897 # warn "ERROR IN ISBD DEFINITION at : $isbdfield" unless $fieldvalue;
898 # warn "FV : $fieldvalue";
899 if ( $subfvalue ne "" ) {
900 foreach my $field (@fieldslist) {
901 foreach my $subfield ( $field->subfield($subfvalue) ) {
902 my $calculated = $analysestring;
903 my $tag = $field->tag();
906 my $subfieldvalue = GetAuthorisedValueDesc
( $tag, $subfvalue, $subfield, '', $tagslib );
907 my $tagsubf = $tag . $subfvalue;
908 $calculated =~ s/\{(.?.?.?.?)$tagsubf(.*?)\}/$1$subfieldvalue$2\{$1$tagsubf$2\}/g;
909 if ( $template eq "opac" ) { $calculated =~ s
#/cgi-bin/koha/[^/]+/([^.]*.pl\?.*)$#opac-$1#g; }
911 # field builded, store the result
912 if ( $calculated && !$hasputtextbefore ) { # put textbefore if not done
913 $blocres .= $textbefore;
914 $hasputtextbefore = 1;
917 # remove punctuation at start
918 $calculated =~ s/^( |;|:|\.|-)*//g;
919 $blocres .= $calculated;
924 $blocres .= $textafter if $hasputtextbefore;
926 foreach my $field (@fieldslist) {
927 my $calculated = $analysestring;
928 my $tag = $field->tag();
931 my @subf = $field->subfields;
932 for my $i ( 0 .. $#subf ) {
933 my $valuecode = $subf[$i][1];
934 my $subfieldcode = $subf[$i][0];
935 my $subfieldvalue = GetAuthorisedValueDesc
( $tag, $subf[$i][0], $subf[$i][1], '', $tagslib );
936 my $tagsubf = $tag . $subfieldcode;
938 $calculated =~ s
/ # replace all {{}} codes by the value code.
939 \
{\
{$tagsubf\
}\
} # catch the {{actualcode}}
941 $valuecode # replace by the value code
944 $calculated =~ s/\{(.?.?.?.?)$tagsubf(.*?)\}/$1$subfieldvalue$2\{$1$tagsubf$2\}/g;
945 if ( $template eq "opac" ) { $calculated =~ s
#/cgi-bin/koha/[^/]+/([^.]*.pl\?.*)$#opac-$1#g; }
948 # field builded, store the result
949 if ( $calculated && !$hasputtextbefore ) { # put textbefore if not done
950 $blocres .= $textbefore;
951 $hasputtextbefore = 1;
954 # remove punctuation at start
955 $calculated =~ s/^( |;|:|\.|-)*//g;
956 $blocres .= $calculated;
959 $blocres .= $textafter if $hasputtextbefore;
962 $blocres .= $isbdfield;
967 $res =~ s/\{(.*?)\}//g;
969 $res =~ s/\n/<br\/>/g
;
979 ( $count, @results ) = &GetBiblio($biblionumber);
984 my ($biblionumber) = @_;
985 my $dbh = C4
::Context
->dbh;
986 my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber = ?");
989 $sth->execute($biblionumber);
990 while ( my $data = $sth->fetchrow_hashref ) {
991 $results[$count] = $data;
995 return ( $count, @results );
998 =head2 GetBiblioItemInfosOf
1000 GetBiblioItemInfosOf(@biblioitemnumbers);
1004 sub GetBiblioItemInfosOf
{
1005 my @biblioitemnumbers = @_;
1008 SELECT biblioitemnumber,
1012 WHERE biblioitemnumber IN (' . join( ',', @biblioitemnumbers ) . ')
1014 return get_infos_of
( $query, 'biblioitemnumber' );
1017 =head1 FUNCTIONS FOR HANDLING MARC MANAGEMENT
1019 =head2 GetMarcStructure
1021 $res = GetMarcStructure($forlibrarian,$frameworkcode);
1023 Returns a reference to a big hash of hash, with the Marc structure for the given frameworkcode
1024 $forlibrarian :if set to 1, the MARC descriptions are the librarians ones, otherwise it's the public (OPAC) ones
1025 $frameworkcode : the framework code to read
1029 # cache for results of GetMarcStructure -- needed
1031 our $marc_structure_cache;
1033 sub GetMarcStructure
{
1034 my ( $forlibrarian, $frameworkcode ) = @_;
1035 my $dbh = C4
::Context
->dbh;
1036 $frameworkcode = "" unless $frameworkcode;
1038 if ( defined $marc_structure_cache and exists $marc_structure_cache->{$forlibrarian}->{$frameworkcode} ) {
1039 return $marc_structure_cache->{$forlibrarian}->{$frameworkcode};
1042 # my $sth = $dbh->prepare(
1043 # "SELECT COUNT(*) FROM marc_tag_structure WHERE frameworkcode=?");
1044 # $sth->execute($frameworkcode);
1045 # my ($total) = $sth->fetchrow;
1046 # $frameworkcode = "" unless ( $total > 0 );
1047 my $sth = $dbh->prepare(
1048 "SELECT tagfield,liblibrarian,libopac,mandatory,repeatable
1049 FROM marc_tag_structure
1050 WHERE frameworkcode=?
1053 $sth->execute($frameworkcode);
1054 my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
1056 while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) = $sth->fetchrow ) {
1057 $res->{$tag}->{lib
} = ( $forlibrarian or !$libopac ) ?
$liblibrarian : $libopac;
1058 $res->{$tag}->{tab
} = "";
1059 $res->{$tag}->{mandatory
} = $mandatory;
1060 $res->{$tag}->{repeatable
} = $repeatable;
1063 $sth = $dbh->prepare(
1064 "SELECT tagfield,tagsubfield,liblibrarian,libopac,tab,mandatory,repeatable,authorised_value,authtypecode,value_builder,kohafield,seealso,hidden,isurl,link,defaultvalue
1065 FROM marc_subfield_structure
1066 WHERE frameworkcode=?
1067 ORDER BY tagfield,tagsubfield
1071 $sth->execute($frameworkcode);
1074 my $authorised_value;
1085 ( $tag, $subfield, $liblibrarian, $libopac, $tab, $mandatory, $repeatable, $authorised_value,
1086 $authtypecode, $value_builder, $kohafield, $seealso, $hidden, $isurl, $link, $defaultvalue
1090 $res->{$tag}->{$subfield}->{lib
} = ( $forlibrarian or !$libopac ) ?
$liblibrarian : $libopac;
1091 $res->{$tag}->{$subfield}->{tab
} = $tab;
1092 $res->{$tag}->{$subfield}->{mandatory
} = $mandatory;
1093 $res->{$tag}->{$subfield}->{repeatable
} = $repeatable;
1094 $res->{$tag}->{$subfield}->{authorised_value
} = $authorised_value;
1095 $res->{$tag}->{$subfield}->{authtypecode
} = $authtypecode;
1096 $res->{$tag}->{$subfield}->{value_builder
} = $value_builder;
1097 $res->{$tag}->{$subfield}->{kohafield
} = $kohafield;
1098 $res->{$tag}->{$subfield}->{seealso
} = $seealso;
1099 $res->{$tag}->{$subfield}->{hidden
} = $hidden;
1100 $res->{$tag}->{$subfield}->{isurl
} = $isurl;
1101 $res->{$tag}->{$subfield}->{'link'} = $link;
1102 $res->{$tag}->{$subfield}->{defaultvalue
} = $defaultvalue;
1105 $marc_structure_cache->{$forlibrarian}->{$frameworkcode} = $res;
1110 =head2 GetUsedMarcStructure
1112 The same function as GetMarcStructure except it just takes field
1113 in tab 0-9. (used field)
1115 my $results = GetUsedMarcStructure($frameworkcode);
1117 C<$results> is a ref to an array which each case containts a ref
1118 to a hash which each keys is the columns from marc_subfield_structure
1120 C<$frameworkcode> is the framework code.
1124 sub GetUsedMarcStructure
($) {
1125 my $frameworkcode = shift || '';
1128 FROM marc_subfield_structure
1130 AND frameworkcode
= ?
1131 ORDER BY tagfield
, tagsubfield
1133 my $sth = C4
::Context
->dbh->prepare($query);
1134 $sth->execute($frameworkcode);
1135 return $sth->fetchall_arrayref( {} );
1138 =head2 GetMarcFromKohaField
1140 ($MARCfield,$MARCsubfield)=GetMarcFromKohaField($kohafield,$frameworkcode);
1142 Returns the MARC fields & subfields mapped to the koha field
1143 for the given frameworkcode
1147 sub GetMarcFromKohaField
{
1148 my ( $kohafield, $frameworkcode ) = @_;
1149 return (0, undef) unless $kohafield and defined $frameworkcode;
1150 my $relations = C4
::Context
->marcfromkohafield;
1151 if ( my $mf = $relations->{$frameworkcode}->{$kohafield} ) {
1157 =head2 GetMarcBiblio
1159 my $record = GetMarcBiblio($biblionumber, [$embeditems]);
1161 Returns MARC::Record representing bib identified by
1162 C<$biblionumber>. If no bib exists, returns undef.
1163 C<$embeditems>. If set to true, items data are included.
1164 The MARC record contains biblio data, and items data if $embeditems is set to true.
1169 my $biblionumber = shift;
1170 my $embeditems = shift || 0;
1171 my $dbh = C4
::Context
->dbh;
1172 my $sth = $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
1173 $sth->execute($biblionumber);
1174 my $row = $sth->fetchrow_hashref;
1175 my $marcxml = StripNonXmlChars
( $row->{'marcxml'} );
1176 MARC
::File
::XML
->default_record_format( C4
::Context
->preference('marcflavour') );
1177 my $record = MARC
::Record
->new();
1180 $record = eval { MARC
::Record
::new_from_xml
( $marcxml, "utf8", C4
::Context
->preference('marcflavour') ) };
1181 if ($@
) { warn " problem with :$biblionumber : $@ \n$marcxml"; }
1182 return unless $record;
1184 C4
::Biblio
::_koha_marc_update_bib_ids
($record, '', $biblionumber, $biblionumber);
1185 C4
::Biblio
::EmbedItemsInMarcBiblio
($record, $biblionumber) if ($embeditems);
1195 my $marcxml = GetXmlBiblio($biblionumber);
1197 Returns biblioitems.marcxml of the biblionumber passed in parameter.
1198 The XML contains both biblio & item datas
1203 my ($biblionumber) = @_;
1204 my $dbh = C4
::Context
->dbh;
1205 my $sth = $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
1206 $sth->execute($biblionumber);
1207 my ($marcxml) = $sth->fetchrow;
1211 =head2 GetCOinSBiblio
1213 my $coins = GetCOinSBiblio($record);
1215 Returns the COinS (a span) which can be included in a biblio record
1219 sub GetCOinSBiblio
{
1222 # get the coin format
1226 my $pos7 = substr $record->leader(), 7, 1;
1227 my $pos6 = substr $record->leader(), 6, 1;
1230 my ( $aulast, $aufirst ) = ( '', '' );
1239 my $titletype = 'b';
1241 # For the purposes of generating COinS metadata, LDR/06-07 can be
1242 # considered the same for UNIMARC and MARC21
1247 'b' => 'manuscript',
1249 'd' => 'manuscript',
1253 'i' => 'audioRecording',
1254 'j' => 'audioRecording',
1257 'm' => 'computerProgram',
1262 'a' => 'journalArticle',
1266 $genre = $fmts6->{$pos6} ?
$fmts6->{$pos6} : 'book';
1268 if ( $genre eq 'book' ) {
1269 $genre = $fmts7->{$pos7} if $fmts7->{$pos7};
1272 ##### We must transform mtx to a valable mtx and document type ####
1273 if ( $genre eq 'book' ) {
1275 } elsif ( $genre eq 'journal' ) {
1278 } elsif ( $genre eq 'journalArticle' ) {
1286 $genre = ( $mtx eq 'dc' ) ?
"&rft.type=$genre" : "&rft.genre=$genre";
1288 if ( C4
::Context
->preference("marcflavour") eq "UNIMARC" ) {
1291 $aulast = $record->subfield( '700', 'a' ) || '';
1292 $aufirst = $record->subfield( '700', 'b' ) || '';
1293 $oauthors = "&rft.au=$aufirst $aulast";
1296 if ( $record->field('200') ) {
1297 for my $au ( $record->field('200')->subfield('g') ) {
1298 $oauthors .= "&rft.au=$au";
1303 ?
"&rft.title=" . $record->subfield( '200', 'a' )
1304 : "&rft.title=" . $record->subfield( '200', 'a' ) . "&rft.btitle=" . $record->subfield( '200', 'a' );
1305 $pubyear = $record->subfield( '210', 'd' ) || '';
1306 $publisher = $record->subfield( '210', 'c' ) || '';
1307 $isbn = $record->subfield( '010', 'a' ) || '';
1308 $issn = $record->subfield( '011', 'a' ) || '';
1311 # MARC21 need some improve
1314 if ( $record->field('100') ) {
1315 $oauthors .= "&rft.au=" . $record->subfield( '100', 'a' );
1319 if ( $record->field('700') ) {
1320 for my $au ( $record->field('700')->subfield('a') ) {
1321 $oauthors .= "&rft.au=$au";
1324 $title = "&rft." . $titletype . "title=" . $record->subfield( '245', 'a' );
1325 $subtitle = $record->subfield( '245', 'b' ) || '';
1326 $title .= $subtitle;
1327 if ($titletype eq 'a') {
1328 $pubyear = $record->field('008') || '';
1329 $pubyear = substr($pubyear->data(), 7, 4) if $pubyear;
1330 $isbn = $record->subfield( '773', 'z' ) || '';
1331 $issn = $record->subfield( '773', 'x' ) || '';
1332 if ($mtx eq 'journal') {
1333 $title .= "&rft.title=" . (($record->subfield( '773', 't' ) || $record->subfield( '773', 'a')));
1335 $title .= "&rft.btitle=" . (($record->subfield( '773', 't' ) || $record->subfield( '773', 'a')) || '');
1337 foreach my $rel ($record->subfield( '773', 'g' )) {
1344 $pubyear = $record->subfield( '260', 'c' ) || '';
1345 $publisher = $record->subfield( '260', 'b' ) || '';
1346 $isbn = $record->subfield( '020', 'a' ) || '';
1347 $issn = $record->subfield( '022', 'a' ) || '';
1352 "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&rft.pages=$pages";
1353 $coins_value =~ s/(\ |&[^a])/\+/g;
1354 $coins_value =~ s/\"/\"\;/g;
1356 #<!-- 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="
1358 return $coins_value;
1364 return the prices in accordance with the Marc format.
1368 my ( $record, $marcflavour ) = @_;
1372 if ( $marcflavour eq "MARC21" ) {
1373 @listtags = ('345', '020');
1375 } elsif ( $marcflavour eq "UNIMARC" ) {
1376 @listtags = ('345', '010');
1382 for my $field ( $record->field(@listtags) ) {
1383 for my $subfield_value ($field->subfield($subfield)){
1385 return $subfield_value if ($subfield_value);
1388 return 0; # no price found
1391 =head2 GetMarcQuantity
1393 return the quantity of a book. Used in acquisition only, when importing a file an iso2709 from a bookseller
1394 Warning : this is not really in the marc standard. In Unimarc, Electre (the most widely used bookseller) use the 969$a
1398 sub GetMarcQuantity
{
1399 my ( $record, $marcflavour ) = @_;
1403 if ( $marcflavour eq "MARC21" ) {
1405 } elsif ( $marcflavour eq "UNIMARC" ) {
1406 @listtags = ('969');
1412 for my $field ( $record->field(@listtags) ) {
1413 for my $subfield_value ($field->subfield($subfield)){
1415 if ($subfield_value) {
1416 # in France, the cents separator is the , but sometimes, ppl use a .
1417 # in this case, the price will be x100 when unformatted ! Replace the . by a , to get a proper price calculation
1418 $subfield_value =~ s/\./,/ if C4
::Context
->preference("CurrencyFormat") eq "FR";
1419 return $subfield_value;
1423 return 0; # no price found
1427 =head2 GetAuthorisedValueDesc
1429 my $subfieldvalue =get_authorised_value_desc(
1430 $tag, $subf[$i][0],$subf[$i][1], '', $taglib, $category, $opac);
1432 Retrieve the complete description for a given authorised value.
1434 Now takes $category and $value pair too.
1436 my $auth_value_desc =GetAuthorisedValueDesc(
1437 '','', 'DVD' ,'','','CCODE');
1439 If the optional $opac parameter is set to a true value, displays OPAC
1440 descriptions rather than normal ones when they exist.
1444 sub GetAuthorisedValueDesc
{
1445 my ( $tag, $subfield, $value, $framework, $tagslib, $category, $opac ) = @_;
1446 my $dbh = C4
::Context
->dbh;
1450 return $value unless defined $tagslib->{$tag}->{$subfield}->{'authorised_value'};
1453 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
1454 return C4
::Branch
::GetBranchName
($value);
1458 if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "itemtypes" ) {
1459 return getitemtypeinfo
($value)->{description
};
1462 #---- "true" authorized value
1463 $category = $tagslib->{$tag}->{$subfield}->{'authorised_value'};
1466 if ( $category ne "" ) {
1467 my $sth = $dbh->prepare( "SELECT lib, lib_opac FROM authorised_values WHERE category = ? AND authorised_value = ?" );
1468 $sth->execute( $category, $value );
1469 my $data = $sth->fetchrow_hashref;
1470 return ( $opac && $data->{'lib_opac'} ) ?
$data->{'lib_opac'} : $data->{'lib'};
1472 return $value; # if nothing is found return the original value
1476 =head2 GetMarcControlnumber
1478 $marccontrolnumber = GetMarcControlnumber($record,$marcflavour);
1480 Get the control number / record Identifier from the MARC record and return it.
1484 sub GetMarcControlnumber
{
1485 my ( $record, $marcflavour ) = @_;
1486 my $controlnumber = "";
1487 # Control number or Record identifier are the same field in MARC21, UNIMARC and NORMARC
1488 # Keep $marcflavour for possible later use
1489 if ($marcflavour eq "MARC21" || $marcflavour eq "UNIMARC" || $marcflavour eq "NORMARC") {
1490 my $controlnumberField = $record->field('001');
1491 if ($controlnumberField) {
1492 $controlnumber = $controlnumberField->data();
1495 return $controlnumber;
1500 $marcisbnsarray = GetMarcISBN( $record, $marcflavour );
1502 Get all ISBNs from the MARC record and returns them in an array.
1503 ISBNs stored in different fields depending on MARC flavour
1508 my ( $record, $marcflavour ) = @_;
1510 if ( $marcflavour eq "UNIMARC" ) {
1512 } else { # assume marc21 if not unimarc
1519 foreach my $field ( $record->field($scope) ) {
1520 my $value = $field->as_string();
1521 if ( $isbn ne "" ) {
1522 $marcisbn = { marcisbn
=> $isbn, };
1523 push @marcisbns, $marcisbn;
1526 if ( $isbn ne $value ) {
1527 $isbn = $isbn . " " . $value;
1532 $marcisbn = { marcisbn
=> $isbn };
1533 push @marcisbns, $marcisbn; #load last tag into array
1541 $marcissnsarray = GetMarcISSN( $record, $marcflavour );
1543 Get all valid ISSNs from the MARC record and returns them in an array.
1544 ISSNs are stored in different fields depending on MARC flavour
1549 my ( $record, $marcflavour ) = @_;
1551 if ( $marcflavour eq "UNIMARC" ) {
1554 else { # assume MARC21 or NORMARC
1558 foreach my $field ( $record->field($scope) ) {
1559 push @marcissns, $field->subfield( 'a' );
1566 $marcnotesarray = GetMarcNotes( $record, $marcflavour );
1568 Get all notes from the MARC record and returns them in an array.
1569 The note are stored in different fields depending on MARC flavour
1574 my ( $record, $marcflavour ) = @_;
1576 if ( $marcflavour eq "UNIMARC" ) {
1578 } else { # assume marc21 if not unimarc
1585 foreach my $field ( $record->field($scope) ) {
1586 my $value = $field->as_string();
1587 if ( $note ne "" ) {
1588 $marcnote = { marcnote
=> $note, };
1589 push @marcnotes, $marcnote;
1592 if ( $note ne $value ) {
1593 $note = $note . " " . $value;
1598 $marcnote = { marcnote
=> $note };
1599 push @marcnotes, $marcnote; #load last tag into array
1602 } # end GetMarcNotes
1604 =head2 GetMarcSubjects
1606 $marcsubjcts = GetMarcSubjects($record,$marcflavour);
1608 Get all subjects from the MARC record and returns them in an array.
1609 The subjects are stored in different fields depending on MARC flavour
1613 sub GetMarcSubjects
{
1614 my ( $record, $marcflavour ) = @_;
1615 my ( $mintag, $maxtag );
1616 if ( $marcflavour eq "UNIMARC" ) {
1619 } else { # assume marc21 if not unimarc
1629 my $subject_limit = C4
::Context
->preference("TraceCompleteSubfields") ?
'su,complete-subfield' : 'su';
1631 foreach my $field ( $record->field('6..') ) {
1632 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1634 my @subfields = $field->subfields();
1638 # if there is an authority link, build the link with an= subfield9
1640 for my $subject_subfield (@subfields) {
1642 # don't load unimarc subfields 3,4,5
1643 next if ( ( $marcflavour eq "UNIMARC" ) and ( $subject_subfield->[0] =~ /2|3|4|5/ ) );
1645 # don't load MARC21 subfields 2 (FIXME: any more subfields??)
1646 next if ( ( $marcflavour eq "MARC21" ) and ( $subject_subfield->[0] =~ /2/ ) );
1647 my $code = $subject_subfield->[0];
1648 my $value = $subject_subfield->[1];
1649 my $linkvalue = $value;
1650 $linkvalue =~ s/(\(|\))//g;
1652 if ( $counter != 0 ) {
1653 $operator = ' and ';
1657 @link_loop = ( { 'limit' => 'an', link => "$linkvalue" } );
1659 if ( not $found9 ) {
1660 push @link_loop, { 'limit' => $subject_limit, link => $linkvalue, operator
=> $operator };
1663 if ( $counter != 0 ) {
1664 $separator = C4
::Context
->preference('authoritysep');
1668 my @this_link_loop = @link_loop;
1669 push @subfields_loop, { code
=> $code, value
=> $value, link_loop
=> \
@this_link_loop, separator
=> $separator } unless ( $subject_subfield->[0] eq 9 );
1673 push @marcsubjects, { MARCSUBJECT_SUBFIELDS_LOOP
=> \
@subfields_loop };
1676 return \
@marcsubjects;
1677 } #end getMARCsubjects
1679 =head2 GetMarcAuthors
1681 authors = GetMarcAuthors($record,$marcflavour);
1683 Get all authors from the MARC record and returns them in an array.
1684 The authors are stored in different fields depending on MARC flavour
1688 sub GetMarcAuthors
{
1689 my ( $record, $marcflavour ) = @_;
1690 my ( $mintag, $maxtag );
1692 # tagslib useful for UNIMARC author reponsabilities
1694 &GetMarcStructure
( 1, '' ); # FIXME : we don't have the framework available, we take the default framework. May be buggy on some setups, will be usually correct.
1695 if ( $marcflavour eq "UNIMARC" ) {
1698 } elsif ( $marcflavour eq "MARC21" || $marcflavour eq "NORMARC" ) { # assume marc21 or normarc if not unimarc
1706 foreach my $field ( $record->fields ) {
1707 next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
1710 my @subfields = $field->subfields();
1713 # if there is an authority link, build the link with Koha-Auth-Number: subfield9
1714 my $subfield9 = $field->subfield('9');
1715 for my $authors_subfield (@subfields) {
1717 # don't load unimarc subfields 3, 5
1718 next if ( $marcflavour eq 'UNIMARC' and ( $authors_subfield->[0] =~ /3|5/ ) );
1719 my $subfieldcode = $authors_subfield->[0];
1720 my $value = $authors_subfield->[1];
1721 my $linkvalue = $value;
1722 $linkvalue =~ s/(\(|\))//g;
1724 if ( $count_auth != 0 ) {
1725 $operator = ' and ';
1728 # if we have an authority link, use that as the link, otherwise use standard searching
1730 @link_loop = ( { 'limit' => 'an', link => "$subfield9" } );
1733 # reset $linkvalue if UNIMARC author responsibility
1734 if ( $marcflavour eq 'UNIMARC' and ( $authors_subfield->[0] eq "4" ) ) {
1735 $linkvalue = "(" . GetAuthorisedValueDesc
( $field->tag(), $authors_subfield->[0], $authors_subfield->[1], '', $tagslib ) . ")";
1737 push @link_loop, { 'limit' => 'au', link => $linkvalue, operator
=> $operator };
1739 $value = GetAuthorisedValueDesc
( $field->tag(), $authors_subfield->[0], $authors_subfield->[1], '', $tagslib )
1740 if ( $marcflavour eq 'UNIMARC' and ( $authors_subfield->[0] =~ /4/ ) );
1741 my @this_link_loop = @link_loop;
1743 if ( $count_auth != 0 ) {
1744 $separator = C4
::Context
->preference('authoritysep');
1746 push @subfields_loop,
1747 { tag
=> $field->tag(),
1748 code
=> $subfieldcode,
1750 link_loop
=> \
@this_link_loop,
1751 separator
=> $separator
1753 unless ( $authors_subfield->[0] eq '9' );
1756 push @marcauthors, { MARCAUTHOR_SUBFIELDS_LOOP
=> \
@subfields_loop };
1758 return \
@marcauthors;
1763 $marcurls = GetMarcUrls($record,$marcflavour);
1765 Returns arrayref of URLs from MARC data, suitable to pass to tmpl loop.
1766 Assumes web resources (not uncommon in MARC21 to omit resource type ind)
1771 my ( $record, $marcflavour ) = @_;
1774 for my $field ( $record->field('856') ) {
1776 for my $note ( $field->subfield('z') ) {
1777 push @notes, { note
=> $note };
1779 my @urls = $field->subfield('u');
1780 foreach my $url (@urls) {
1782 if ( $marcflavour eq 'MARC21' ) {
1783 my $s3 = $field->subfield('3');
1784 my $link = $field->subfield('y');
1785 unless ( $url =~ /^\w+:/ ) {
1786 if ( $field->indicator(1) eq '7' ) {
1787 $url = $field->subfield('2') . "://" . $url;
1788 } elsif ( $field->indicator(1) eq '1' ) {
1789 $url = 'ftp://' . $url;
1792 # properly, this should be if ind1=4,
1793 # however we will assume http protocol since we're building a link.
1794 $url = 'http://' . $url;
1798 # TODO handle ind 2 (relationship)
1803 $marcurl->{'linktext'} = $link || $s3 || C4
::Context
->preference('URLLinkText') || $url;
1804 $marcurl->{'part'} = $s3 if ($link);
1805 $marcurl->{'toc'} = 1 if ( defined($s3) && $s3 =~ /^[Tt]able/ );
1807 $marcurl->{'linktext'} = $field->subfield('2') || C4
::Context
->preference('URLLinkText') || $url;
1808 $marcurl->{'MARCURL'} = $url;
1810 push @marcurls, $marcurl;
1816 =head2 GetMarcSeries
1818 $marcseriesarray = GetMarcSeries($record,$marcflavour);
1820 Get all series from the MARC record and returns them in an array.
1821 The series are stored in different fields depending on MARC flavour
1826 my ( $record, $marcflavour ) = @_;
1827 my ( $mintag, $maxtag );
1828 if ( $marcflavour eq "UNIMARC" ) {
1831 } else { # assume marc21 if not unimarc
1841 foreach my $field ( $record->field('440'), $record->field('490') ) {
1844 #my $value = $field->subfield('a');
1845 #$marcsubjct = {MARCSUBJCT => $value,};
1846 my @subfields = $field->subfields();
1848 #warn "subfields:".join " ", @$subfields;
1851 for my $series_subfield (@subfields) {
1853 undef $volume_number;
1855 # see if this is an instance of a volume
1856 if ( $series_subfield->[0] eq 'v' ) {
1860 my $code = $series_subfield->[0];
1861 my $value = $series_subfield->[1];
1862 my $linkvalue = $value;
1863 $linkvalue =~ s/(\(|\))//g;
1864 if ( $counter != 0 ) {
1865 push @link_loop, { link => $linkvalue, operator
=> ' and ', };
1867 push @link_loop, { link => $linkvalue, operator
=> undef, };
1870 if ( $counter != 0 ) {
1871 $separator = C4
::Context
->preference('authoritysep');
1873 if ($volume_number) {
1874 push @subfields_loop, { volumenum
=> $value };
1876 if ( $series_subfield->[0] ne '9' ) {
1877 push @subfields_loop, {
1880 link_loop
=> \
@link_loop,
1881 separator
=> $separator,
1882 volumenum
=> $volume_number,
1888 push @marcseries, { MARCSERIES_SUBFIELDS_LOOP
=> \
@subfields_loop };
1890 #$marcsubjct = {MARCSUBJCT => $field->as_string(),};
1891 #push @marcsubjcts, $marcsubjct;
1895 my $marcseriessarray = \
@marcseries;
1896 return $marcseriessarray;
1897 } #end getMARCseriess
1901 $marchostsarray = GetMarcHosts($record,$marcflavour);
1903 Get all host records (773s MARC21, 461 UNIMARC) from the MARC record and returns them in an array.
1908 my ( $record, $marcflavour ) = @_;
1909 my ( $tag,$title_subf,$bibnumber_subf,$itemnumber_subf);
1910 $marcflavour ||="MARC21";
1911 if ( $marcflavour eq "MARC21" || $marcflavour eq "NORMARC" ) {
1914 $bibnumber_subf ="0";
1915 $itemnumber_subf='9';
1917 elsif ($marcflavour eq "UNIMARC") {
1920 $bibnumber_subf ="0";
1921 $itemnumber_subf='9';
1926 foreach my $field ( $record->field($tag)) {
1930 my $hostbiblionumber = $field->subfield("$bibnumber_subf");
1931 my $hosttitle = $field->subfield($title_subf);
1932 my $hostitemnumber=$field->subfield($itemnumber_subf);
1933 push @fields_loop, { hostbiblionumber
=> $hostbiblionumber, hosttitle
=> $hosttitle, hostitemnumber
=> $hostitemnumber};
1934 push @marchosts, { MARCHOSTS_FIELDS_LOOP
=> \
@fields_loop };
1937 my $marchostsarray = \
@marchosts;
1938 return $marchostsarray;
1941 =head2 GetFrameworkCode
1943 $frameworkcode = GetFrameworkCode( $biblionumber )
1947 sub GetFrameworkCode
{
1948 my ($biblionumber) = @_;
1949 my $dbh = C4
::Context
->dbh;
1950 my $sth = $dbh->prepare("SELECT frameworkcode FROM biblio WHERE biblionumber=?");
1951 $sth->execute($biblionumber);
1952 my ($frameworkcode) = $sth->fetchrow;
1953 return $frameworkcode;
1956 =head2 TransformKohaToMarc
1958 $record = TransformKohaToMarc( $hash )
1960 This function builds partial MARC::Record from a hash
1961 Hash entries can be from biblio or biblioitems.
1963 This function is called in acquisition module, to create a basic catalogue
1964 entry from user entry
1969 sub TransformKohaToMarc
{
1971 my $record = MARC
::Record
->new();
1972 SetMarcUnicodeFlag
( $record, C4
::Context
->preference("marcflavour") );
1973 my $db_to_marc = C4
::Context
->marcfromkohafield;
1974 while ( my ($name, $value) = each %$hash ) {
1975 next unless my $dtm = $db_to_marc->{''}->{$name};
1976 my ($tag, $letter) = @
$dtm;
1977 foreach my $value ( split(/\s?\|\s?/, $value, -1) ) {
1978 if ( my $field = $record->field($tag) ) {
1979 $field->add_subfields( $letter => $value );
1982 $record->insert_fields_ordered( MARC
::Field
->new(
1983 $tag, " ", " ", $letter => $value ) );
1991 =head2 PrepHostMarcField
1993 $hostfield = PrepHostMarcField ( $hostbiblionumber,$hostitemnumber,$marcflavour )
1995 This function returns a host field populated with data from the host record, the field can then be added to an analytical record
1999 sub PrepHostMarcField
{
2000 my ($hostbiblionumber,$hostitemnumber, $marcflavour) = @_;
2001 $marcflavour ||="MARC21";
2004 my $hostrecord = GetMarcBiblio
($hostbiblionumber);
2005 my $item = C4
::Items
::GetItem
($hostitemnumber);
2008 if ( $marcflavour eq "MARC21" || $marcflavour eq "NORMARC" ) {
2012 if ($hostrecord->subfield('100','a')){
2013 $mainentry = $hostrecord->subfield('100','a');
2014 } elsif ($hostrecord->subfield('110','a')){
2015 $mainentry = $hostrecord->subfield('110','a');
2017 $mainentry = $hostrecord->subfield('111','a');
2020 # qualification info
2022 if (my $field260 = $hostrecord->field('260')){
2023 $qualinfo = $field260->as_string( 'abc' );
2028 my $ed = $hostrecord->subfield('250','a');
2029 my $barcode = $item->{'barcode'};
2030 my $title = $hostrecord->subfield('245','a');
2032 # record control number, 001 with 003 and prefix
2034 if ($hostrecord->field('001')){
2035 $recctrlno = $hostrecord->field('001')->data();
2036 if ($hostrecord->field('003')){
2037 $recctrlno = '('.$hostrecord->field('003')->data().')'.$recctrlno;
2042 my $issn = $hostrecord->subfield('022','a');
2043 my $isbn = $hostrecord->subfield('020','a');
2046 $hostmarcfield = MARC
::Field
->new(
2048 '0' => $hostbiblionumber,
2049 '9' => $hostitemnumber,
2059 } elsif ($marcflavour eq "UNIMARC") {
2060 $hostmarcfield = MARC
::Field
->new(
2062 '0' => $hostbiblionumber,
2063 't' => $hostrecord->subfield('200','a'),
2064 '9' => $hostitemnumber
2068 return $hostmarcfield;
2071 =head2 TransformHtmlToXml
2073 $xml = TransformHtmlToXml( $tags, $subfields, $values, $indicator,
2074 $ind_tag, $auth_type )
2076 $auth_type contains :
2080 =item - nothing : rebuild a biblio. In UNIMARC the encoding is in 100$a pos 26/27
2082 =item - UNIMARCAUTH : rebuild an authority. In UNIMARC, the encoding is in 100$a pos 13/14
2084 =item - ITEM : rebuild an item : in UNIMARC, 100$a, it's in the biblio ! (otherwise, we would get 2 100 fields !)
2090 sub TransformHtmlToXml
{
2091 my ( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type ) = @_;
2092 my $xml = MARC
::File
::XML
::header
('UTF-8');
2093 $xml .= "<record>\n";
2094 $auth_type = C4
::Context
->preference('marcflavour') unless $auth_type;
2095 MARC
::File
::XML
->default_record_format($auth_type);
2097 # in UNIMARC, field 100 contains the encoding
2098 # check that there is one, otherwise the
2099 # MARC::Record->new_from_xml will fail (and Koha will die)
2100 my $unimarc_and_100_exist = 0;
2101 $unimarc_and_100_exist = 1 if $auth_type eq 'ITEM'; # if we rebuild an item, no need of a 100 field
2106 for ( my $i = 0 ; $i < @
$tags ; $i++ ) {
2108 if ( C4
::Context
->preference('marcflavour') eq 'UNIMARC' and @
$tags[$i] eq "100" and @
$subfields[$i] eq "a" ) {
2110 # if we have a 100 field and it's values are not correct, skip them.
2111 # if we don't have any valid 100 field, we will create a default one at the end
2112 my $enc = substr( @
$values[$i], 26, 2 );
2113 if ( $enc eq '01' or $enc eq '50' or $enc eq '03' ) {
2114 $unimarc_and_100_exist = 1;
2119 @
$values[$i] =~ s/&/&/g;
2120 @
$values[$i] =~ s/</</g;
2121 @
$values[$i] =~ s/>/>/g;
2122 @
$values[$i] =~ s/"/"/g;
2123 @
$values[$i] =~ s/'/'/g;
2125 # if ( !utf8::is_utf8( @$values[$i] ) ) {
2126 # utf8::decode( @$values[$i] );
2128 if ( ( @
$tags[$i] ne $prevtag ) ) {
2129 $j++ unless ( @
$tags[$i] eq "" );
2130 my $indicator1 = eval { substr( @
$indicator[$j], 0, 1 ) };
2131 my $indicator2 = eval { substr( @
$indicator[$j], 1, 1 ) };
2132 my $ind1 = _default_ind_to_space
($indicator1);
2134 if ( @
$indicator[$j] ) {
2135 $ind2 = _default_ind_to_space
($indicator2);
2137 warn "Indicator in @$tags[$i] is empty";
2141 $xml .= "</datafield>\n";
2142 if ( ( @
$tags[$i] && @
$tags[$i] > 10 )
2143 && ( @
$values[$i] ne "" ) ) {
2144 $xml .= "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
2145 $xml .= "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2151 if ( @
$values[$i] ne "" ) {
2154 if ( @
$tags[$i] eq "000" ) {
2155 $xml .= "<leader>@$values[$i]</leader>\n";
2158 # rest of the fixed fields
2159 } elsif ( @
$tags[$i] < 10 ) {
2160 $xml .= "<controlfield tag=\"@$tags[$i]\">@$values[$i]</controlfield>\n";
2163 $xml .= "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
2164 $xml .= "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2169 } else { # @$tags[$i] eq $prevtag
2170 my $indicator1 = eval { substr( @
$indicator[$j], 0, 1 ) };
2171 my $indicator2 = eval { substr( @
$indicator[$j], 1, 1 ) };
2172 my $ind1 = _default_ind_to_space
($indicator1);
2174 if ( @
$indicator[$j] ) {
2175 $ind2 = _default_ind_to_space
($indicator2);
2177 warn "Indicator in @$tags[$i] is empty";
2180 if ( @
$values[$i] eq "" ) {
2183 $xml .= "<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
2186 $xml .= "<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
2189 $prevtag = @
$tags[$i];
2191 $xml .= "</datafield>\n" if $xml =~ m
/<datafield
/;
2192 if ( C4
::Context
->preference('marcflavour') eq 'UNIMARC' and !$unimarc_and_100_exist ) {
2194 # warn "SETTING 100 for $auth_type";
2195 my $string = strftime
( "%Y%m%d", localtime(time) );
2197 # set 50 to position 26 is biblios, 13 if authorities
2199 $pos = 13 if $auth_type eq 'UNIMARCAUTH';
2200 $string = sprintf( "%-*s", 35, $string );
2201 substr( $string, $pos, 6, "50" );
2202 $xml .= "<datafield tag=\"100\" ind1=\"\" ind2=\"\">\n";
2203 $xml .= "<subfield code=\"a\">$string</subfield>\n";
2204 $xml .= "</datafield>\n";
2206 $xml .= "</record>\n";
2207 $xml .= MARC
::File
::XML
::footer
();
2211 =head2 _default_ind_to_space
2213 Passed what should be an indicator returns a space
2214 if its undefined or zero length
2218 sub _default_ind_to_space
{
2220 if ( !defined $s || $s eq q{} ) {
2226 =head2 TransformHtmlToMarc
2228 L<$record> = TransformHtmlToMarc(L<$cgi>)
2229 L<$cgi> is the CGI object which containts the values for subfields
2231 'tag_010_indicator1_531951' ,
2232 'tag_010_indicator2_531951' ,
2233 'tag_010_code_a_531951_145735' ,
2234 'tag_010_subfield_a_531951_145735' ,
2235 'tag_200_indicator1_873510' ,
2236 'tag_200_indicator2_873510' ,
2237 'tag_200_code_a_873510_673465' ,
2238 'tag_200_subfield_a_873510_673465' ,
2239 'tag_200_code_b_873510_704318' ,
2240 'tag_200_subfield_b_873510_704318' ,
2241 'tag_200_code_e_873510_280822' ,
2242 'tag_200_subfield_e_873510_280822' ,
2243 'tag_200_code_f_873510_110730' ,
2244 'tag_200_subfield_f_873510_110730' ,
2246 L<$record> is the MARC::Record object.
2250 sub TransformHtmlToMarc
{
2253 my @params = $cgi->param();
2255 # explicitly turn on the UTF-8 flag for all
2256 # 'tag_' parameters to avoid incorrect character
2257 # conversion later on
2258 my $cgi_params = $cgi->Vars;
2259 foreach my $param_name ( keys %$cgi_params ) {
2260 if ( $param_name =~ /^tag_/ ) {
2261 my $param_value = $cgi_params->{$param_name};
2262 if ( utf8
::decode
($param_value) ) {
2263 $cgi_params->{$param_name} = $param_value;
2266 # FIXME - need to do something if string is not valid UTF-8
2270 # creating a new record
2271 my $record = MARC
::Record
->new();
2274 #FIXME This code assumes that the CGI params will be in the same order as the fields in the template; this is no absolute guarantee!
2275 while ( $params[$i] ) { # browse all CGI params
2276 my $param = $params[$i];
2279 # if we are on biblionumber, store it in the MARC::Record (it may not be in the edited fields)
2280 if ( $param eq 'biblionumber' ) {
2281 my ( $biblionumbertagfield, $biblionumbertagsubfield ) = &GetMarcFromKohaField
( "biblio.biblionumber", '' );
2282 if ( $biblionumbertagfield < 10 ) {
2283 $newfield = MARC
::Field
->new( $biblionumbertagfield, $cgi->param($param), );
2285 $newfield = MARC
::Field
->new( $biblionumbertagfield, '', '', "$biblionumbertagsubfield" => $cgi->param($param), );
2287 push @fields, $newfield if ($newfield);
2288 } elsif ( $param =~ /^tag_(\d*)_indicator1_/ ) { # new field start when having 'input name="..._indicator1_..."
2291 my $ind1 = _default_ind_to_space
( substr( $cgi->param($param), 0, 1 ) );
2292 my $ind2 = _default_ind_to_space
( substr( $cgi->param( $params[ $i + 1 ] ), 0, 1 ) );
2296 if ( $tag < 10 ) { # no code for theses fields
2297 # in MARC editor, 000 contains the leader.
2298 if ( $tag eq '000' ) {
2299 # Force a fake leader even if not provided to avoid crashing
2300 # during decoding MARC record containing UTF-8 characters
2302 length( $cgi->param($params[$j+1]) ) == 24
2303 ?
$cgi->param( $params[ $j + 1 ] )
2307 # between 001 and 009 (included)
2308 } elsif ( $cgi->param( $params[ $j + 1 ] ) ne '' ) {
2309 $newfield = MARC
::Field
->new( $tag, $cgi->param( $params[ $j + 1 ] ), );
2312 # > 009, deal with subfields
2314 # browse subfields for this tag (reason for _code_ match)
2315 while(defined $params[$j] && $params[$j] =~ /_code_/) {
2316 last unless defined $params[$j+1];
2317 #if next param ne subfield, then it was probably empty
2318 #try next param by incrementing j
2319 if($params[$j+1]!~/_subfield_/) {$j++; next; }
2320 my $fval= $cgi->param($params[$j+1]);
2321 #check if subfield value not empty and field exists
2322 if($fval ne '' && $newfield) {
2323 $newfield->add_subfields( $cgi->param($params[$j]) => $fval);
2325 elsif($fval ne '') {
2326 $newfield = MARC
::Field
->new( $tag, $ind1, $ind2, $cgi->param($params[$j]) => $fval );
2330 $i= $j-1; #update i for outer loop accordingly
2332 push @fields, $newfield if ($newfield);
2337 $record->append_fields(@fields);
2341 # cache inverted MARC field map
2342 our $inverted_field_map;
2344 =head2 TransformMarcToKoha
2346 $result = TransformMarcToKoha( $dbh, $record, $frameworkcode )
2348 Extract data from a MARC bib record into a hashref representing
2349 Koha biblio, biblioitems, and items fields.
2353 sub TransformMarcToKoha
{
2354 my ( $dbh, $record, $frameworkcode, $limit_table ) = @_;
2357 $limit_table = $limit_table || 0;
2358 $frameworkcode = '' unless defined $frameworkcode;
2360 unless ( defined $inverted_field_map ) {
2361 $inverted_field_map = _get_inverted_marc_field_map
();
2365 if ( defined $limit_table && $limit_table eq 'items' ) {
2366 $tables{'items'} = 1;
2368 $tables{'items'} = 1;
2369 $tables{'biblio'} = 1;
2370 $tables{'biblioitems'} = 1;
2373 # traverse through record
2374 MARCFIELD
: foreach my $field ( $record->fields() ) {
2375 my $tag = $field->tag();
2376 next MARCFIELD
unless exists $inverted_field_map->{$frameworkcode}->{$tag};
2377 if ( $field->is_control_field() ) {
2378 my $kohafields = $inverted_field_map->{$frameworkcode}->{$tag}->{list
};
2379 ENTRY
: foreach my $entry ( @
{$kohafields} ) {
2380 my ( $subfield, $table, $column ) = @
{$entry};
2381 next ENTRY
unless exists $tables{$table};
2382 my $key = _disambiguate
( $table, $column );
2383 if ( $result->{$key} ) {
2384 unless ( ( $key eq "biblionumber" or $key eq "biblioitemnumber" ) and ( $field->data() eq "" ) ) {
2385 $result->{$key} .= " | " . $field->data();
2388 $result->{$key} = $field->data();
2393 # deal with subfields
2394 MARCSUBFIELD
: foreach my $sf ( $field->subfields() ) {
2395 my $code = $sf->[0];
2396 next MARCSUBFIELD
unless exists $inverted_field_map->{$frameworkcode}->{$tag}->{sfs
}->{$code};
2397 my $value = $sf->[1];
2398 SFENTRY
: foreach my $entry ( @
{ $inverted_field_map->{$frameworkcode}->{$tag}->{sfs
}->{$code} } ) {
2399 my ( $table, $column ) = @
{$entry};
2400 next SFENTRY
unless exists $tables{$table};
2401 my $key = _disambiguate
( $table, $column );
2402 if ( $result->{$key} ) {
2403 unless ( ( $key eq "biblionumber" or $key eq "biblioitemnumber" ) and ( $value eq "" ) ) {
2404 $result->{$key} .= " | " . $value;
2407 $result->{$key} = $value;
2414 # modify copyrightdate to keep only the 1st year found
2415 if ( exists $result->{'copyrightdate'} ) {
2416 my $temp = $result->{'copyrightdate'};
2417 $temp =~ m/c(\d\d\d\d)/;
2418 if ( $temp =~ m/c(\d\d\d\d)/ and $1 > 0 ) { # search cYYYY first
2419 $result->{'copyrightdate'} = $1;
2420 } else { # if no cYYYY, get the 1st date.
2421 $temp =~ m/(\d\d\d\d)/;
2422 $result->{'copyrightdate'} = $1;
2426 # modify publicationyear to keep only the 1st year found
2427 if ( exists $result->{'publicationyear'} ) {
2428 my $temp = $result->{'publicationyear'};
2429 if ( $temp =~ m/c(\d\d\d\d)/ and $1 > 0 ) { # search cYYYY first
2430 $result->{'publicationyear'} = $1;
2431 } else { # if no cYYYY, get the 1st date.
2432 $temp =~ m/(\d\d\d\d)/;
2433 $result->{'publicationyear'} = $1;
2440 sub _get_inverted_marc_field_map
{
2442 my $relations = C4
::Context
->marcfromkohafield;
2444 foreach my $frameworkcode ( keys %{$relations} ) {
2445 foreach my $kohafield ( keys %{ $relations->{$frameworkcode} } ) {
2446 next unless @
{ $relations->{$frameworkcode}->{$kohafield} }; # not all columns are mapped to MARC tag & subfield
2447 my $tag = $relations->{$frameworkcode}->{$kohafield}->[0];
2448 my $subfield = $relations->{$frameworkcode}->{$kohafield}->[1];
2449 my ( $table, $column ) = split /[.]/, $kohafield, 2;
2450 push @
{ $field_map->{$frameworkcode}->{$tag}->{list
} }, [ $subfield, $table, $column ];
2451 push @
{ $field_map->{$frameworkcode}->{$tag}->{sfs
}->{$subfield} }, [ $table, $column ];
2457 =head2 _disambiguate
2459 $newkey = _disambiguate($table, $field);
2461 This is a temporary hack to distinguish between the
2462 following sets of columns when using TransformMarcToKoha.
2464 items.cn_source & biblioitems.cn_source
2465 items.cn_sort & biblioitems.cn_sort
2467 Columns that are currently NOT distinguished (FIXME
2468 due to lack of time to fully test) are:
2470 biblio.notes and biblioitems.notes
2475 FIXME - this is necessary because prefixing each column
2476 name with the table name would require changing lots
2477 of code and templates, and exposing more of the DB
2478 structure than is good to the UI templates, particularly
2479 since biblio and bibloitems may well merge in a future
2480 version. In the future, it would also be good to
2481 separate DB access and UI presentation field names
2486 sub CountItemsIssued
{
2487 my ($biblionumber) = @_;
2488 my $dbh = C4
::Context
->dbh;
2489 my $sth = $dbh->prepare('SELECT COUNT(*) as issuedCount FROM items, issues WHERE items.itemnumber = issues.itemnumber AND items.biblionumber = ?');
2490 $sth->execute($biblionumber);
2491 my $row = $sth->fetchrow_hashref();
2492 return $row->{'issuedCount'};
2496 my ( $table, $column ) = @_;
2497 if ( $column eq "cn_sort" or $column eq "cn_source" ) {
2498 return $table . '.' . $column;
2505 =head2 get_koha_field_from_marc
2507 $result->{_disambiguate($table, $field)} =
2508 get_koha_field_from_marc($table,$field,$record,$frameworkcode);
2510 Internal function to map data from the MARC record to a specific non-MARC field.
2511 FIXME: this is meant to replace TransformMarcToKohaOneField after more testing.
2515 sub get_koha_field_from_marc
{
2516 my ( $koha_table, $koha_column, $record, $frameworkcode ) = @_;
2517 my ( $tagfield, $subfield ) = GetMarcFromKohaField
( $koha_table . '.' . $koha_column, $frameworkcode );
2519 foreach my $field ( $record->field($tagfield) ) {
2520 if ( $field->tag() < 10 ) {
2522 $kohafield .= " | " . $field->data();
2524 $kohafield = $field->data();
2527 if ( $field->subfields ) {
2528 my @subfields = $field->subfields();
2529 foreach my $subfieldcount ( 0 .. $#subfields ) {
2530 if ( $subfields[$subfieldcount][0] eq $subfield ) {
2532 $kohafield .= " | " . $subfields[$subfieldcount][1];
2534 $kohafield = $subfields[$subfieldcount][1];
2544 =head2 TransformMarcToKohaOneField
2546 $result = TransformMarcToKohaOneField( $kohatable, $kohafield, $record, $result, $frameworkcode )
2550 sub TransformMarcToKohaOneField
{
2552 # FIXME ? if a field has a repeatable subfield that is used in old-db,
2553 # only the 1st will be retrieved...
2554 my ( $kohatable, $kohafield, $record, $result, $frameworkcode ) = @_;
2556 my ( $tagfield, $subfield ) = GetMarcFromKohaField
( $kohatable . "." . $kohafield, $frameworkcode );
2557 foreach my $field ( $record->field($tagfield) ) {
2558 if ( $field->tag() < 10 ) {
2559 if ( $result->{$kohafield} ) {
2560 $result->{$kohafield} .= " | " . $field->data();
2562 $result->{$kohafield} = $field->data();
2565 if ( $field->subfields ) {
2566 my @subfields = $field->subfields();
2567 foreach my $subfieldcount ( 0 .. $#subfields ) {
2568 if ( $subfields[$subfieldcount][0] eq $subfield ) {
2569 if ( $result->{$kohafield} ) {
2570 $result->{$kohafield} .= " | " . $subfields[$subfieldcount][1];
2572 $result->{$kohafield} = $subfields[$subfieldcount][1];
2586 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2588 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2589 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2590 # =head2 ModZebrafiles
2592 # &ModZebrafiles( $dbh, $biblionumber, $record, $folder, $server );
2596 # sub ModZebrafiles {
2598 # my ( $dbh, $biblionumber, $record, $folder, $server ) = @_;
2602 # C4::Context->zebraconfig($server)->{directory} . "/" . $folder . "/";
2603 # unless ( opendir( DIR, "$zebradir" ) ) {
2604 # warn "$zebradir not found";
2608 # my $filename = $zebradir . $biblionumber;
2611 # open( OUTPUT, ">", $filename . ".xml" );
2612 # print OUTPUT $record;
2619 ModZebra( $biblionumber, $op, $server, $oldRecord, $newRecord );
2621 $biblionumber is the biblionumber we want to index
2623 $op is specialUpdate or delete, and is used to know what we want to do
2625 $server is the server that we want to update
2627 $oldRecord is the MARC::Record containing the previous version of the record. This is used only when
2628 NoZebra=1, as NoZebra indexing needs to know the previous version of a record in order to
2631 $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.
2636 ###Accepts a $server variable thus we can use it for biblios authorities or other zebra dbs
2637 my ( $biblionumber, $op, $server, $oldRecord, $newRecord ) = @_;
2638 my $dbh = C4
::Context
->dbh;
2640 # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
2642 # replaced by a zebraqueue table, that is filled with ModZebra to run.
2643 # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
2645 if ( C4
::Context
->preference("NoZebra") ) {
2647 # lock the nozebra table : we will read index lines, update them in Perl process
2648 # and write everything in 1 transaction.
2649 # lock the table to avoid someone else overwriting what we are doing
2650 $dbh->do('LOCK TABLES nozebra WRITE,biblio WRITE,biblioitems WRITE, systempreferences WRITE, auth_types WRITE, auth_header WRITE, auth_subfield_structure READ');
2651 my %result; # the result hash that will be built by deletion / add, and written on mySQL at the end, to improve speed
2652 if ( $op eq 'specialUpdate' ) {
2654 # OK, we have to add or update the record
2655 # 1st delete (virtually, in indexes), if record actually exists
2657 %result = _DelBiblioNoZebra
( $biblionumber, $oldRecord, $server );
2660 # ... add the record
2661 %result = _AddBiblioNoZebra
( $biblionumber, $newRecord, $server, %result );
2664 # it's a deletion, delete the record...
2665 # warn "DELETE the record $biblionumber on $server".$record->as_formatted;
2666 %result = _DelBiblioNoZebra
( $biblionumber, $oldRecord, $server );
2669 # ok, now update the database...
2670 my $sth = $dbh->prepare("UPDATE nozebra SET biblionumbers=? WHERE server=? AND indexname=? AND value=?");
2671 foreach my $key ( keys %result ) {
2672 foreach my $index ( keys %{ $result{$key} } ) {
2673 $sth->execute( $result{$key}->{$index}, $server, $key, $index );
2676 $dbh->do('UNLOCK TABLES');
2680 # we use zebra, just fill zebraqueue table
2682 my $check_sql = "SELECT COUNT(*) FROM zebraqueue
2684 AND biblio_auth_number = ?
2687 my $check_sth = $dbh->prepare_cached($check_sql);
2688 $check_sth->execute( $server, $biblionumber, $op );
2689 my ($count) = $check_sth->fetchrow_array;
2690 $check_sth->finish();
2691 if ( $count == 0 ) {
2692 my $sth = $dbh->prepare("INSERT INTO zebraqueue (biblio_auth_number,server,operation) VALUES(?,?,?)");
2693 $sth->execute( $biblionumber, $server, $op );
2699 =head2 GetNoZebraIndexes
2701 %indexes = GetNoZebraIndexes;
2703 return the data from NoZebraIndexes syspref.
2707 sub GetNoZebraIndexes
{
2708 my $no_zebra_indexes = C4
::Context
->preference('NoZebraIndexes');
2710 INDEX
: foreach my $line ( split /['"],[\n\r]*/, $no_zebra_indexes ) {
2711 $line =~ /(.*)=>(.*)/;
2712 my $index = $1; # initial ' or " is removed afterwards
2714 $index =~ s/'|"|\s//g;
2715 $fields =~ s/'|"|\s//g;
2716 $indexes{$index} = $fields;
2721 =head2 EmbedItemsInMarcBiblio
2723 EmbedItemsInMarcBiblio($marc, $biblionumber);
2725 Given a MARC::Record object containing a bib record,
2726 modify it to include the items attached to it as 9XX
2727 per the bib's MARC framework.
2731 sub EmbedItemsInMarcBiblio
{
2732 my ($marc, $biblionumber) = @_;
2733 croak
"No MARC record" unless $marc;
2735 my $frameworkcode = GetFrameworkCode
($biblionumber);
2736 _strip_item_fields
($marc, $frameworkcode);
2738 # ... and embed the current items
2739 my $dbh = C4
::Context
->dbh;
2740 my $sth = $dbh->prepare("SELECT itemnumber FROM items WHERE biblionumber = ?");
2741 $sth->execute($biblionumber);
2743 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField
( "items.itemnumber", $frameworkcode );
2744 while (my ($itemnumber) = $sth->fetchrow_array) {
2746 my $item_marc = C4
::Items
::GetMarcItem
($biblionumber, $itemnumber);
2747 push @item_fields, $item_marc->field($itemtag);
2749 $marc->append_fields(@item_fields);
2752 =head1 INTERNAL FUNCTIONS
2754 =head2 _DelBiblioNoZebra($biblionumber,$record,$server);
2756 function to delete a biblio in NoZebra indexes
2757 This function does NOT delete anything in database : it reads all the indexes entries
2758 that have to be deleted & delete them in the hash
2760 The SQL part is done either :
2761 - after the Add if we are modifying a biblio (delete + add again)
2762 - immediatly after this sub if we are doing a true deletion.
2764 $server can be 'biblioserver' or 'authorityserver' : it indexes biblios or authorities (in the same table, $server being part of the table itself
2768 sub _DelBiblioNoZebra
{
2769 my ( $biblionumber, $record, $server ) = @_;
2772 my $dbh = C4
::Context
->dbh;
2777 if ( $server eq 'biblioserver' ) {
2778 %index = GetNoZebraIndexes
;
2780 # get title of the record (to store the 10 first letters with the index)
2781 my ( $titletag, $titlesubfield ) = GetMarcFromKohaField
( 'biblio.title', '' ); # FIXME: should be GetFrameworkCode($biblionumber) ??
2782 $title = lc( $record->subfield( $titletag, $titlesubfield ) );
2785 # for authorities, the "title" is the $a mainentry
2786 my ( $auth_type_tag, $auth_type_sf ) = C4
::AuthoritiesMarc
::get_auth_type_location
();
2787 my $authref = C4
::AuthoritiesMarc
::GetAuthType
( $record->subfield( $auth_type_tag, $auth_type_sf ) );
2788 warn "ERROR : authtype undefined for " . $record->as_formatted unless $authref;
2789 $title = $record->subfield( $authref->{auth_tag_to_report
}, 'a' );
2790 $index{'mainmainentry'} = $authref->{'auth_tag_to_report'} . 'a';
2791 $index{'mainentry'} = $authref->{'auth_tag_to_report'} . '*';
2792 $index{'auth_type'} = "${auth_type_tag}${auth_type_sf}";
2797 # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
2798 $title =~ s/ |,|;|\[|\]|\(|\)|\*|-|'|=//g;
2800 # limit to 10 char, should be enough, and limit the DB size
2801 $title = substr( $title, 0, 10 );
2804 my $sth2 = $dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
2805 foreach my $field ( $record->fields() ) {
2807 #parse each subfield
2808 next if $field->tag < 10;
2809 foreach my $subfield ( $field->subfields() ) {
2810 my $tag = $field->tag();
2811 my $subfieldcode = $subfield->[0];
2814 # check each index to see if the subfield is stored somewhere
2815 # otherwise, store it in __RAW__ index
2816 foreach my $key ( keys %index ) {
2818 # warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
2819 if ( $index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/ ) {
2821 my $line = lc $subfield->[1];
2823 # remove meaningless value in the field...
2824 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g
;
2826 # ... and split in words
2827 foreach ( split / /, $line ) {
2828 next unless $_; # skip empty values (multiple spaces)
2829 # if the entry is already here, do nothing, the biblionumber has already be removed
2830 unless ( defined( $result{$key}->{$_} ) && ( $result{$key}->{$_} =~ /$biblionumber,$title\-(\d);/ ) ) {
2832 # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
2833 $sth2->execute( $server, $key, $_ );
2834 my $existing_biblionumbers = $sth2->fetchrow;
2837 if ($existing_biblionumbers) {
2839 # warn " existing for $key $_: $existing_biblionumbers";
2840 $result{$key}->{$_} = $existing_biblionumbers;
2841 $result{$key}->{$_} =~ s/$biblionumber,$title\-(\d);//;
2848 # the subfield is not indexed, store it in __RAW__ index anyway
2850 my $line = lc $subfield->[1];
2851 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g
;
2853 # ... and split in words
2854 foreach ( split / /, $line ) {
2855 next unless $_; # skip empty values (multiple spaces)
2856 # if the entry is already here, do nothing, the biblionumber has already be removed
2857 unless ( $result{'__RAW__'}->{$_} =~ /$biblionumber,$title\-(\d);/ ) {
2859 # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
2860 $sth2->execute( $server, '__RAW__', $_ );
2861 my $existing_biblionumbers = $sth2->fetchrow;
2864 if ($existing_biblionumbers) {
2865 $result{'__RAW__'}->{$_} = $existing_biblionumbers;
2866 $result{'__RAW__'}->{$_} =~ s/$biblionumber,$title\-(\d);//;
2876 =head2 _AddBiblioNoZebra
2878 _AddBiblioNoZebra($biblionumber, $record, $server, %result);
2880 function to add a biblio in NoZebra indexes
2884 sub _AddBiblioNoZebra
{
2885 my ( $biblionumber, $record, $server, %result ) = @_;
2886 my $dbh = C4
::Context
->dbh;
2891 if ( $server eq 'biblioserver' ) {
2892 %index = GetNoZebraIndexes
;
2894 # get title of the record (to store the 10 first letters with the index)
2895 my ( $titletag, $titlesubfield ) = GetMarcFromKohaField
( 'biblio.title', '' ); # FIXME: should be GetFrameworkCode($biblionumber) ??
2896 $title = lc( $record->subfield( $titletag, $titlesubfield ) );
2899 # warn "server : $server";
2900 # for authorities, the "title" is the $a mainentry
2901 my ( $auth_type_tag, $auth_type_sf ) = C4
::AuthoritiesMarc
::get_auth_type_location
();
2902 my $authref = C4
::AuthoritiesMarc
::GetAuthType
( $record->subfield( $auth_type_tag, $auth_type_sf ) );
2903 warn "ERROR : authtype undefined for " . $record->as_formatted unless $authref;
2904 $title = $record->subfield( $authref->{auth_tag_to_report
}, 'a' );
2905 $index{'mainmainentry'} = $authref->{auth_tag_to_report
} . 'a';
2906 $index{'mainentry'} = $authref->{auth_tag_to_report
} . '*';
2907 $index{'auth_type'} = "${auth_type_tag}${auth_type_sf}";
2910 # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
2911 $title =~ s/ |\.|,|;|\[|\]|\(|\)|\*|-|'|:|=|\r|\n//g;
2913 # limit to 10 char, should be enough, and limit the DB size
2914 $title = substr( $title, 0, 10 );
2917 my $sth2 = $dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
2918 foreach my $field ( $record->fields() ) {
2920 #parse each subfield
2921 ###FIXME: impossible to index a 001-009 value with NoZebra
2922 next if $field->tag < 10;
2923 foreach my $subfield ( $field->subfields() ) {
2924 my $tag = $field->tag();
2925 my $subfieldcode = $subfield->[0];
2928 # warn "INDEXING :".$subfield->[1];
2929 # check each index to see if the subfield is stored somewhere
2930 # otherwise, store it in __RAW__ index
2931 foreach my $key ( keys %index ) {
2933 # warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
2934 if ( $index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/ ) {
2936 my $line = lc $subfield->[1];
2938 # remove meaningless value in the field...
2939 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:|\r|\n/ /g
;
2941 # ... and split in words
2942 foreach ( split / /, $line ) {
2943 next unless $_; # skip empty values (multiple spaces)
2944 # if the entry is already here, improve weight
2946 # warn "managing $_";
2947 if ( exists $result{$key}->{$_} && $result{$key}->{"$_"} =~ /$biblionumber,\Q$title\E\-(\d+);/ ) {
2948 my $weight = $1 + 1;
2949 $result{$key}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//g;
2950 $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
2953 # get the value if it exist in the nozebra table, otherwise, create it
2954 $sth2->execute( $server, $key, $_ );
2955 my $existing_biblionumbers = $sth2->fetchrow;
2958 if ($existing_biblionumbers) {
2959 $result{$key}->{"$_"} = $existing_biblionumbers;
2960 my $weight = defined $1 ?
$1 + 1 : 1;
2961 $result{$key}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//g;
2962 $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
2964 # create a new ligne for this entry
2967 # warn "INSERT : $server / $key / $_";
2968 $dbh->do( 'INSERT INTO nozebra SET server=' . $dbh->quote($server) . ', indexname=' . $dbh->quote($key) . ',value=' . $dbh->quote($_) );
2969 $result{$key}->{"$_"} .= "$biblionumber,$title-1;";
2976 # the subfield is not indexed, store it in __RAW__ index anyway
2978 my $line = lc $subfield->[1];
2979 $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:|\r|\n/ /g
;
2981 # ... and split in words
2982 foreach ( split / /, $line ) {
2983 next unless $_; # skip empty values (multiple spaces)
2984 # if the entry is already here, improve weight
2985 my $tmpstr = $result{'__RAW__'}->{"$_"} || "";
2986 if ( $tmpstr =~ /$biblionumber,\Q$title\E\-(\d+);/ ) {
2987 my $weight = $1 + 1;
2988 $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//;
2989 $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
2992 # get the value if it exist in the nozebra table, otherwise, create it
2993 $sth2->execute( $server, '__RAW__', $_ );
2994 my $existing_biblionumbers = $sth2->fetchrow;
2997 if ($existing_biblionumbers) {
2998 $result{'__RAW__'}->{"$_"} = $existing_biblionumbers;
2999 my $weight = ( $1 ?
$1 : 0 ) + 1;
3000 $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//;
3001 $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
3003 # create a new ligne for this entry
3005 $dbh->do( 'INSERT INTO nozebra SET server=' . $dbh->quote($server) . ', indexname="__RAW__",value=' . $dbh->quote($_) );
3006 $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-1;";
3016 =head2 _koha_marc_update_bib_ids
3019 _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
3021 Internal function to add or update biblionumber and biblioitemnumber to
3026 sub _koha_marc_update_bib_ids
{
3027 my ( $record, $frameworkcode, $biblionumber, $biblioitemnumber ) = @_;
3029 # we must add bibnum and bibitemnum in MARC::Record...
3030 # we build the new field with biblionumber and biblioitemnumber
3031 # we drop the original field
3032 # we add the new builded field.
3033 my ( $biblio_tag, $biblio_subfield ) = GetMarcFromKohaField
( "biblio.biblionumber", $frameworkcode );
3034 die qq{No biblionumber tag
for framework
"$frameworkcode"} unless $biblio_tag;
3035 my ( $biblioitem_tag, $biblioitem_subfield ) = GetMarcFromKohaField
( "biblioitems.biblioitemnumber", $frameworkcode );
3036 die qq{No biblioitemnumber tag
for framework
"$frameworkcode"} unless $biblio_tag;
3038 if ( $biblio_tag == $biblioitem_tag ) {
3040 # biblionumber & biblioitemnumber are in the same field (can't be <10 as fields <10 have only 1 value)
3041 my $new_field = MARC
::Field
->new(
3042 $biblio_tag, '', '',
3043 "$biblio_subfield" => $biblionumber,
3044 "$biblioitem_subfield" => $biblioitemnumber
3047 # drop old field and create new one...
3048 my $old_field = $record->field($biblio_tag);
3049 $record->delete_field($old_field) if $old_field;
3050 $record->insert_fields_ordered($new_field);
3053 # biblionumber & biblioitemnumber are in different fields
3055 # deal with biblionumber
3056 my ( $new_field, $old_field );
3057 if ( $biblio_tag < 10 ) {
3058 $new_field = MARC
::Field
->new( $biblio_tag, $biblionumber );
3060 $new_field = MARC
::Field
->new( $biblio_tag, '', '', "$biblio_subfield" => $biblionumber );
3063 # drop old field and create new one...
3064 $old_field = $record->field($biblio_tag);
3065 $record->delete_field($old_field) if $old_field;
3066 $record->insert_fields_ordered($new_field);
3068 # deal with biblioitemnumber
3069 if ( $biblioitem_tag < 10 ) {
3070 $new_field = MARC
::Field
->new( $biblioitem_tag, $biblioitemnumber, );
3072 $new_field = MARC
::Field
->new( $biblioitem_tag, '', '', "$biblioitem_subfield" => $biblioitemnumber, );
3075 # drop old field and create new one...
3076 $old_field = $record->field($biblioitem_tag);
3077 $record->delete_field($old_field) if $old_field;
3078 $record->insert_fields_ordered($new_field);
3082 =head2 _koha_marc_update_biblioitem_cn_sort
3084 _koha_marc_update_biblioitem_cn_sort($marc, $biblioitem, $frameworkcode);
3086 Given a MARC bib record and the biblioitem hash, update the
3087 subfield that contains a copy of the value of biblioitems.cn_sort.
3091 sub _koha_marc_update_biblioitem_cn_sort
{
3093 my $biblioitem = shift;
3094 my $frameworkcode = shift;
3096 my ( $biblioitem_tag, $biblioitem_subfield ) = GetMarcFromKohaField
( "biblioitems.cn_sort", $frameworkcode );
3097 return unless $biblioitem_tag;
3099 my ($cn_sort) = GetClassSort
( $biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
3101 if ( my $field = $marc->field($biblioitem_tag) ) {
3102 $field->delete_subfield( code
=> $biblioitem_subfield );
3103 if ( $cn_sort ne '' ) {
3104 $field->add_subfields( $biblioitem_subfield => $cn_sort );
3108 # if we get here, no biblioitem tag is present in the MARC record, so
3109 # we'll create it if $cn_sort is not empty -- this would be
3110 # an odd combination of events, however
3112 $marc->insert_grouped_field( MARC
::Field
->new( $biblioitem_tag, ' ', ' ', $biblioitem_subfield => $cn_sort ) );
3117 =head2 _koha_add_biblio
3119 my ($biblionumber,$error) = _koha_add_biblio($dbh,$biblioitem);
3121 Internal function to add a biblio ($biblio is a hash with the values)
3125 sub _koha_add_biblio
{
3126 my ( $dbh, $biblio, $frameworkcode ) = @_;
3130 # set the series flag
3131 unless (defined $biblio->{'serial'}){
3132 $biblio->{'serial'} = 0;
3133 if ( $biblio->{'seriestitle'} ) { $biblio->{'serial'} = 1 }
3136 my $query = "INSERT INTO biblio
3137 SET frameworkcode = ?,
3148 my $sth = $dbh->prepare($query);
3150 $frameworkcode, $biblio->{'author'}, $biblio->{'title'}, $biblio->{'unititle'}, $biblio->{'notes'},
3151 $biblio->{'serial'}, $biblio->{'seriestitle'}, $biblio->{'copyrightdate'}, $biblio->{'abstract'}
3154 my $biblionumber = $dbh->{'mysql_insertid'};
3155 if ( $dbh->errstr ) {
3156 $error .= "ERROR in _koha_add_biblio $query" . $dbh->errstr;
3162 #warn "LEAVING _koha_add_biblio: ".$biblionumber."\n";
3163 return ( $biblionumber, $error );
3166 =head2 _koha_modify_biblio
3168 my ($biblionumber,$error) == _koha_modify_biblio($dbh,$biblio,$frameworkcode);
3170 Internal function for updating the biblio table
3174 sub _koha_modify_biblio
{
3175 my ( $dbh, $biblio, $frameworkcode ) = @_;
3180 SET frameworkcode = ?,
3189 WHERE biblionumber = ?
3192 my $sth = $dbh->prepare($query);
3195 $frameworkcode, $biblio->{'author'}, $biblio->{'title'}, $biblio->{'unititle'}, $biblio->{'notes'},
3196 $biblio->{'serial'}, $biblio->{'seriestitle'}, $biblio->{'copyrightdate'}, $biblio->{'abstract'}, $biblio->{'biblionumber'}
3197 ) if $biblio->{'biblionumber'};
3199 if ( $dbh->errstr || !$biblio->{'biblionumber'} ) {
3200 $error .= "ERROR in _koha_modify_biblio $query" . $dbh->errstr;
3203 return ( $biblio->{'biblionumber'}, $error );
3206 =head2 _koha_modify_biblioitem_nonmarc
3208 my ($biblioitemnumber,$error) = _koha_modify_biblioitem_nonmarc( $dbh, $biblioitem );
3210 Updates biblioitems row except for marc and marcxml, which should be changed
3215 sub _koha_modify_biblioitem_nonmarc
{
3216 my ( $dbh, $biblioitem ) = @_;
3219 # re-calculate the cn_sort, it may have changed
3220 my ($cn_sort) = GetClassSort
( $biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
3222 my $query = "UPDATE biblioitems
3223 SET biblionumber = ?,
3229 publicationyear = ?,
3233 collectiontitle = ?,
3235 collectionvolume= ?,
3236 editionstatement= ?,
3237 editionresponsibility = ?,
3251 where biblioitemnumber = ?
3253 my $sth = $dbh->prepare($query);
3255 $biblioitem->{'biblionumber'}, $biblioitem->{'volume'}, $biblioitem->{'number'}, $biblioitem->{'itemtype'},
3256 $biblioitem->{'isbn'}, $biblioitem->{'issn'}, $biblioitem->{'publicationyear'}, $biblioitem->{'publishercode'},
3257 $biblioitem->{'volumedate'}, $biblioitem->{'volumedesc'}, $biblioitem->{'collectiontitle'}, $biblioitem->{'collectionissn'},
3258 $biblioitem->{'collectionvolume'}, $biblioitem->{'editionstatement'}, $biblioitem->{'editionresponsibility'}, $biblioitem->{'illus'},
3259 $biblioitem->{'pages'}, $biblioitem->{'bnotes'}, $biblioitem->{'size'}, $biblioitem->{'place'},
3260 $biblioitem->{'lccn'}, $biblioitem->{'url'}, $biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'},
3261 $biblioitem->{'cn_item'}, $biblioitem->{'cn_suffix'}, $cn_sort, $biblioitem->{'totalissues'},
3262 $biblioitem->{'biblioitemnumber'}
3264 if ( $dbh->errstr ) {
3265 $error .= "ERROR in _koha_modify_biblioitem_nonmarc $query" . $dbh->errstr;
3268 return ( $biblioitem->{'biblioitemnumber'}, $error );
3271 =head2 _koha_add_biblioitem
3273 my ($biblioitemnumber,$error) = _koha_add_biblioitem( $dbh, $biblioitem );
3275 Internal function to add a biblioitem
3279 sub _koha_add_biblioitem
{
3280 my ( $dbh, $biblioitem ) = @_;
3283 my ($cn_sort) = GetClassSort
( $biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
3284 my $query = "INSERT INTO biblioitems SET
3291 publicationyear = ?,
3295 collectiontitle = ?,
3297 collectionvolume= ?,
3298 editionstatement= ?,
3299 editionresponsibility = ?,
3315 my $sth = $dbh->prepare($query);
3317 $biblioitem->{'biblionumber'}, $biblioitem->{'volume'}, $biblioitem->{'number'}, $biblioitem->{'itemtype'},
3318 $biblioitem->{'isbn'}, $biblioitem->{'issn'}, $biblioitem->{'publicationyear'}, $biblioitem->{'publishercode'},
3319 $biblioitem->{'volumedate'}, $biblioitem->{'volumedesc'}, $biblioitem->{'collectiontitle'}, $biblioitem->{'collectionissn'},
3320 $biblioitem->{'collectionvolume'}, $biblioitem->{'editionstatement'}, $biblioitem->{'editionresponsibility'}, $biblioitem->{'illus'},
3321 $biblioitem->{'pages'}, $biblioitem->{'bnotes'}, $biblioitem->{'size'}, $biblioitem->{'place'},
3322 $biblioitem->{'lccn'}, $biblioitem->{'marc'}, $biblioitem->{'url'}, $biblioitem->{'biblioitems.cn_source'},
3323 $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'}, $biblioitem->{'cn_suffix'}, $cn_sort,
3324 $biblioitem->{'totalissues'}
3326 my $bibitemnum = $dbh->{'mysql_insertid'};
3328 if ( $dbh->errstr ) {
3329 $error .= "ERROR in _koha_add_biblioitem $query" . $dbh->errstr;
3333 return ( $bibitemnum, $error );
3336 =head2 _koha_delete_biblio
3338 $error = _koha_delete_biblio($dbh,$biblionumber);
3340 Internal sub for deleting from biblio table -- also saves to deletedbiblio
3342 C<$dbh> - the database handle
3344 C<$biblionumber> - the biblionumber of the biblio to be deleted
3348 # FIXME: add error handling
3350 sub _koha_delete_biblio
{
3351 my ( $dbh, $biblionumber ) = @_;
3353 # get all the data for this biblio
3354 my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber=?");
3355 $sth->execute($biblionumber);
3357 if ( my $data = $sth->fetchrow_hashref ) {
3359 # save the record in deletedbiblio
3360 # find the fields to save
3361 my $query = "INSERT INTO deletedbiblio SET ";
3363 foreach my $temp ( keys %$data ) {
3364 $query .= "$temp = ?,";
3365 push( @bind, $data->{$temp} );
3368 # replace the last , by ",?)"
3370 my $bkup_sth = $dbh->prepare($query);
3371 $bkup_sth->execute(@bind);
3375 my $sth2 = $dbh->prepare("DELETE FROM biblio WHERE biblionumber=?");
3376 $sth2->execute($biblionumber);
3377 # update the timestamp (Bugzilla 7146)
3378 $sth2= $dbh->prepare("UPDATE deletedbiblio SET timestamp=NOW() WHERE biblionumber=?");
3379 $sth2->execute($biblionumber);
3386 =head2 _koha_delete_biblioitems
3388 $error = _koha_delete_biblioitems($dbh,$biblioitemnumber);
3390 Internal sub for deleting from biblioitems table -- also saves to deletedbiblioitems
3392 C<$dbh> - the database handle
3393 C<$biblionumber> - the biblioitemnumber of the biblioitem to be deleted
3397 # FIXME: add error handling
3399 sub _koha_delete_biblioitems
{
3400 my ( $dbh, $biblioitemnumber ) = @_;
3402 # get all the data for this biblioitem
3403 my $sth = $dbh->prepare("SELECT * FROM biblioitems WHERE biblioitemnumber=?");
3404 $sth->execute($biblioitemnumber);
3406 if ( my $data = $sth->fetchrow_hashref ) {
3408 # save the record in deletedbiblioitems
3409 # find the fields to save
3410 my $query = "INSERT INTO deletedbiblioitems SET ";
3412 foreach my $temp ( keys %$data ) {
3413 $query .= "$temp = ?,";
3414 push( @bind, $data->{$temp} );
3417 # replace the last , by ",?)"
3419 my $bkup_sth = $dbh->prepare($query);
3420 $bkup_sth->execute(@bind);
3423 # delete the biblioitem
3424 my $sth2 = $dbh->prepare("DELETE FROM biblioitems WHERE biblioitemnumber=?");
3425 $sth2->execute($biblioitemnumber);
3426 # update the timestamp (Bugzilla 7146)
3427 $sth2= $dbh->prepare("UPDATE deletedbiblioitems SET timestamp=NOW() WHERE biblioitemnumber=?");
3428 $sth2->execute($biblioitemnumber);
3435 =head1 UNEXPORTED FUNCTIONS
3437 =head2 ModBiblioMarc
3439 &ModBiblioMarc($newrec,$biblionumber,$frameworkcode);
3441 Add MARC data for a biblio to koha
3443 Function exported, but should NOT be used, unless you really know what you're doing
3449 # pass the MARC::Record to this function, and it will create the records in the marc field
3450 my ( $record, $biblionumber, $frameworkcode ) = @_;
3451 my $dbh = C4
::Context
->dbh;
3452 my @fields = $record->fields();
3453 if ( !$frameworkcode ) {
3454 $frameworkcode = "";
3456 my $sth = $dbh->prepare("UPDATE biblio SET frameworkcode=? WHERE biblionumber=?");
3457 $sth->execute( $frameworkcode, $biblionumber );
3459 my $encoding = C4
::Context
->preference("marcflavour");
3461 # deal with UNIMARC field 100 (encoding) : create it if needed & set encoding to unicode
3462 if ( $encoding eq "UNIMARC" ) {
3463 my $string = $record->subfield( 100, "a" );
3464 if ( ($string) && ( length( $record->subfield( 100, "a" ) ) == 36 ) ) {
3465 my $f100 = $record->field(100);
3466 $record->delete_field($f100);
3468 $string = POSIX
::strftime
( "%Y%m%d", localtime );
3470 $string = sprintf( "%-*s", 35, $string );
3472 substr( $string, 22, 6, "frey50" );
3473 unless ( $record->subfield( 100, "a" ) ) {
3474 $record->insert_fields_ordered( MARC
::Field
->new( 100, "", "", "a" => $string ) );
3478 #enhancement 5374: update transaction date (005) for marc21/unimarc
3479 if($encoding =~ /MARC21|UNIMARC/) {
3480 my @a= (localtime) [5,4,3,2,1,0]; $a[0]+=1900; $a[1]++;
3481 # YY MM DD HH MM SS (update year and month)
3482 my $f005= $record->field('005');
3483 $f005->update(sprintf("%4d%02d%02d%02d%02d%04.1f",@a)) if $f005;
3487 if ( C4
::Context
->preference("NoZebra") ) {
3489 # only NoZebra indexing needs to have
3490 # the previous version of the record
3491 $oldRecord = GetMarcBiblio
($biblionumber);
3493 $sth = $dbh->prepare("UPDATE biblioitems SET marc=?,marcxml=? WHERE biblionumber=?");
3494 $sth->execute( $record->as_usmarc(), $record->as_xml_record($encoding), $biblionumber );
3496 ModZebra
( $biblionumber, "specialUpdate", "biblioserver", $oldRecord, $record );
3497 return $biblionumber;
3500 =head2 get_biblio_authorised_values
3502 find the types and values for all authorised values assigned to this biblio.
3506 MARC::Record of the bib
3508 returns: a hashref mapping the authorised value to the value set for this biblionumber
3510 $authorised_values = {
3511 'Scent' => 'flowery',
3512 'Audience' => 'Young Adult',
3513 'itemtypes' => 'SER',
3516 Notes: forlibrarian should probably be passed in, and called something different.
3520 sub get_biblio_authorised_values
{
3521 my $biblionumber = shift;
3524 my $forlibrarian = 1; # are we in staff or opac?
3525 my $frameworkcode = GetFrameworkCode
($biblionumber);
3527 my $authorised_values;
3529 my $tagslib = GetMarcStructure
( $forlibrarian, $frameworkcode )
3530 or return $authorised_values;
3532 # assume that these entries in the authorised_value table are bibliolevel.
3533 # ones that start with 'item%' are item level.
3534 my $query = q
(SELECT distinct authorised_value
, kohafield
3535 FROM marc_subfield_structure
3536 WHERE authorised_value
!=''
3537 AND
(kohafield like
'biblio%'
3538 OR kohafield like
'') );
3539 my $bibliolevel_authorised_values = C4
::Context
->dbh->selectall_hashref( $query, 'authorised_value' );
3541 foreach my $tag ( keys(%$tagslib) ) {
3542 foreach my $subfield ( keys( %{ $tagslib->{$tag} } ) ) {
3544 # warn "checking $subfield. type is: " . ref $tagslib->{ $tag }{ $subfield };
3545 if ( 'HASH' eq ref $tagslib->{$tag}{$subfield} ) {
3546 if ( defined $tagslib->{$tag}{$subfield}{'authorised_value'} && exists $bibliolevel_authorised_values->{ $tagslib->{$tag}{$subfield}{'authorised_value'} } ) {
3547 if ( defined $record->field($tag) ) {
3548 my $this_subfield_value = $record->field($tag)->subfield($subfield);
3549 if ( defined $this_subfield_value ) {
3550 $authorised_values->{ $tagslib->{$tag}{$subfield}{'authorised_value'} } = $this_subfield_value;
3558 # warn ( Data::Dumper->Dump( [ $authorised_values ], [ 'authorised_values' ] ) );
3559 return $authorised_values;
3562 =head2 CountBiblioInOrders
3565 $count = &CountBiblioInOrders( $biblionumber);
3569 This function return count of biblios in orders with $biblionumber
3573 sub CountBiblioInOrders
{
3574 my ($biblionumber) = @_;
3575 my $dbh = C4
::Context
->dbh;
3576 my $query = "SELECT count(*)
3578 WHERE biblionumber=? AND (datecancellationprinted IS NULL OR datecancellationprinted='0000-00-00')";
3579 my $sth = $dbh->prepare($query);
3580 $sth->execute($biblionumber);
3581 my $count = $sth->fetchrow;
3585 =head2 GetSubscriptionsId
3588 $subscriptions = &GetSubscriptionsId($biblionumber);
3592 This function return an array of subscriptionid with $biblionumber
3596 sub GetSubscriptionsId
{
3597 my ($biblionumber) = @_;
3598 my $dbh = C4
::Context
->dbh;
3599 my $query = "SELECT subscriptionid
3601 WHERE biblionumber=?";
3602 my $sth = $dbh->prepare($query);
3603 $sth->execute($biblionumber);
3604 my @subscriptions = $sth->fetchrow_array;
3605 return (@subscriptions);
3611 $holds = &GetHolds($biblionumber);
3615 This function return the count of holds with $biblionumber
3620 my ($biblionumber) = @_;
3621 my $dbh = C4
::Context
->dbh;
3622 my $query = "SELECT count(*)
3624 WHERE biblionumber=?";
3625 my $sth = $dbh->prepare($query);
3626 $sth->execute($biblionumber);
3627 my $holds = $sth->fetchrow;
3638 Koha Development Team <http://koha-community.org/>
3640 Paul POULAIN paul.poulain@free.fr
3642 Joshua Ferraro jmf@liblime.com