Bug 12177 - Remove HTML from authorities.pl
[koha.git] / C4 / Koha.pm
blobee4bd67d4dd342f940e2eac63040cc837c8341c6
1 package C4::Koha;
3 # Copyright 2000-2002 Katipo Communications
4 # Parts Copyright 2010 Nelsonville Public Library
5 # Parts copyright 2010 BibLibre
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
12 # version.
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.
23 use strict;
24 #use warnings; FIXME - Bug 2505
26 use C4::Context;
27 use C4::Branch qw(GetBranchesCount);
28 use Koha::DateUtils qw(dt_from_string);
29 use Memoize;
30 use DateTime::Format::MySQL;
31 use Business::ISBN;
32 use autouse 'Data::Dumper' => qw(Dumper);
33 use DBI qw(:sql_types);
35 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $DEBUG);
37 BEGIN {
38 $VERSION = 3.07.00.049;
39 require Exporter;
40 @ISA = qw(Exporter);
41 @EXPORT = qw(
42 &slashifyDate
43 &subfield_is_koha_internal_p
44 &GetPrinters &GetPrinter
45 &GetItemTypes &getitemtypeinfo
46 &GetSupportName &GetSupportList
47 &get_itemtypeinfos_of
48 &getframeworks &getframeworkinfo
49 &GetFrameworksLoop
50 &getauthtypes &getauthtype
51 &getallthemes
52 &getFacets
53 &displayServers
54 &getnbpages
55 &get_infos_of
56 &get_notforloan_label_of
57 &getitemtypeimagedir
58 &getitemtypeimagesrc
59 &getitemtypeimagelocation
60 &GetAuthorisedValues
61 &GetAuthorisedValueCategories
62 &IsAuthorisedValueCategory
63 &GetKohaAuthorisedValues
64 &GetKohaAuthorisedValuesFromField
65 &GetKohaAuthorisedValueLib
66 &GetAuthorisedValueByCode
67 &GetKohaImageurlFromAuthorisedValues
68 &GetAuthValCode
69 &AddAuthorisedValue
70 &GetNormalizedUPC
71 &GetNormalizedISBN
72 &GetNormalizedEAN
73 &GetNormalizedOCLCNumber
74 &xml_escape
76 &GetVariationsOfISBN
77 &GetVariationsOfISBNs
78 &NormalizeISBN
80 $DEBUG
82 $DEBUG = 0;
83 @EXPORT_OK = qw( GetDailyQuote );
86 # expensive functions
87 memoize('GetAuthorisedValues');
89 =head1 NAME
91 C4::Koha - Perl Module containing convenience functions for Koha scripts
93 =head1 SYNOPSIS
95 use C4::Koha;
97 =head1 DESCRIPTION
99 Koha.pm provides many functions for Koha scripts.
101 =head1 FUNCTIONS
103 =cut
105 =head2 slashifyDate
107 $slash_date = &slashifyDate($dash_date);
109 Takes a string of the form "DD-MM-YYYY" (or anything separated by
110 dashes), converts it to the form "YYYY/MM/DD", and returns the result.
112 =cut
114 sub slashifyDate {
116 # accepts a date of the form xx-xx-xx[xx] and returns it in the
117 # form xx/xx/xx[xx]
118 my @dateOut = split( '-', shift );
119 return ("$dateOut[2]/$dateOut[1]/$dateOut[0]");
122 # FIXME.. this should be moved to a MARC-specific module
123 sub subfield_is_koha_internal_p {
124 my ($subfield) = @_;
126 # We could match on 'lib' and 'tab' (and 'mandatory', & more to come!)
127 # But real MARC subfields are always single-character
128 # so it really is safer just to check the length
130 return length $subfield != 1;
133 =head2 GetSupportName
135 $itemtypename = &GetSupportName($codestring);
137 Returns a string with the name of the itemtype.
139 =cut
141 sub GetSupportName{
142 my ($codestring)=@_;
143 return if (! $codestring);
144 my $resultstring;
145 my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
146 if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') {
147 my $query = qq|
148 SELECT description
149 FROM itemtypes
150 WHERE itemtype=?
151 order by description
153 my $sth = C4::Context->dbh->prepare($query);
154 $sth->execute($codestring);
155 ($resultstring)=$sth->fetchrow;
156 return $resultstring;
157 } else {
158 my $sth =
159 C4::Context->dbh->prepare(
160 "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
162 $sth->execute( $advanced_search_types, $codestring );
163 my $data = $sth->fetchrow_hashref;
164 return $$data{'lib'};
168 =head2 GetSupportList
170 $itemtypes = &GetSupportList();
172 Returns an array ref containing informations about Support (since itemtype is rather a circulation code when item-level-itypes is used).
174 build a HTML select with the following code :
176 =head3 in PERL SCRIPT
178 my $itemtypes = GetSupportList();
179 $template->param(itemtypeloop => $itemtypes);
181 =head3 in TEMPLATE
183 <select name="itemtype" id="itemtype">
184 <option value=""></option>
185 [% FOREACH itemtypeloo IN itemtypeloop %]
186 [% IF ( itemtypeloo.selected ) %]
187 <option value="[% itemtypeloo.itemtype %]" selected="selected">[% itemtypeloo.description %]</option>
188 [% ELSE %]
189 <option value="[% itemtypeloo.itemtype %]">[% itemtypeloo.description %]</option>
190 [% END %]
191 [% END %]
192 </select>
194 =cut
196 sub GetSupportList{
197 my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
198 if (!$advanced_search_types or $advanced_search_types =~ /itemtypes/) {
199 my $query = qq|
200 SELECT *
201 FROM itemtypes
202 order by description
204 my $sth = C4::Context->dbh->prepare($query);
205 $sth->execute;
206 return $sth->fetchall_arrayref({});
207 } else {
208 my $advsearchtypes = GetAuthorisedValues($advanced_search_types);
209 my @results= map {{itemtype=>$$_{authorised_value},description=>$$_{lib},imageurl=>$$_{imageurl}}} @$advsearchtypes;
210 return \@results;
213 =head2 GetItemTypes
215 $itemtypes = &GetItemTypes( style => $style );
217 Returns information about existing itemtypes.
219 Params:
220 style: either 'array' or 'hash', defaults to 'hash'.
221 'array' returns an arrayref,
222 'hash' return a hashref with the itemtype value as the key
224 build a HTML select with the following code :
226 =head3 in PERL SCRIPT
228 my $itemtypes = GetItemTypes;
229 my @itemtypesloop;
230 foreach my $thisitemtype (sort keys %$itemtypes) {
231 my $selected = 1 if $thisitemtype eq $itemtype;
232 my %row =(value => $thisitemtype,
233 selected => $selected,
234 description => $itemtypes->{$thisitemtype}->{'description'},
236 push @itemtypesloop, \%row;
238 $template->param(itemtypeloop => \@itemtypesloop);
240 =head3 in TEMPLATE
242 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
243 <select name="itemtype">
244 <option value="">Default</option>
245 <!-- TMPL_LOOP name="itemtypeloop" -->
246 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="description" --></option>
247 <!-- /TMPL_LOOP -->
248 </select>
249 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
250 <input type="submit" value="OK" class="button">
251 </form>
253 =cut
255 sub GetItemTypes {
256 my ( %params ) = @_;
257 my $style = defined( $params{'style'} ) ? $params{'style'} : 'hash';
259 # returns a reference to a hash of references to itemtypes...
260 my %itemtypes;
261 my $dbh = C4::Context->dbh;
262 my $query = qq|
263 SELECT *
264 FROM itemtypes
266 my $sth = $dbh->prepare($query);
267 $sth->execute;
269 if ( $style eq 'hash' ) {
270 while ( my $IT = $sth->fetchrow_hashref ) {
271 $itemtypes{ $IT->{'itemtype'} } = $IT;
273 return ( \%itemtypes );
274 } else {
275 return $sth->fetchall_arrayref({});
279 sub get_itemtypeinfos_of {
280 my @itemtypes = @_;
282 my $placeholders = join( ', ', map { '?' } @itemtypes );
283 my $query = <<"END_SQL";
284 SELECT itemtype,
285 description,
286 imageurl,
287 notforloan
288 FROM itemtypes
289 WHERE itemtype IN ( $placeholders )
290 END_SQL
292 return get_infos_of( $query, 'itemtype', undef, \@itemtypes );
295 =head2 getauthtypes
297 $authtypes = &getauthtypes();
299 Returns information about existing authtypes.
301 build a HTML select with the following code :
303 =head3 in PERL SCRIPT
305 my $authtypes = getauthtypes;
306 my @authtypesloop;
307 foreach my $thisauthtype (keys %$authtypes) {
308 my $selected = 1 if $thisauthtype eq $authtype;
309 my %row =(value => $thisauthtype,
310 selected => $selected,
311 authtypetext => $authtypes->{$thisauthtype}->{'authtypetext'},
313 push @authtypesloop, \%row;
315 $template->param(itemtypeloop => \@itemtypesloop);
317 =head3 in TEMPLATE
319 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
320 <select name="authtype">
321 <!-- TMPL_LOOP name="authtypeloop" -->
322 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="authtypetext" --></option>
323 <!-- /TMPL_LOOP -->
324 </select>
325 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
326 <input type="submit" value="OK" class="button">
327 </form>
330 =cut
332 sub getauthtypes {
334 # returns a reference to a hash of references to authtypes...
335 my %authtypes;
336 my $dbh = C4::Context->dbh;
337 my $sth = $dbh->prepare("select * from auth_types order by authtypetext");
338 $sth->execute;
339 while ( my $IT = $sth->fetchrow_hashref ) {
340 $authtypes{ $IT->{'authtypecode'} } = $IT;
342 return ( \%authtypes );
345 sub getauthtype {
346 my ($authtypecode) = @_;
348 # returns a reference to a hash of references to authtypes...
349 my %authtypes;
350 my $dbh = C4::Context->dbh;
351 my $sth = $dbh->prepare("select * from auth_types where authtypecode=?");
352 $sth->execute($authtypecode);
353 my $res = $sth->fetchrow_hashref;
354 return $res;
357 =head2 getframework
359 $frameworks = &getframework();
361 Returns information about existing frameworks
363 build a HTML select with the following code :
365 =head3 in PERL SCRIPT
367 my $frameworks = getframeworks();
368 my @frameworkloop;
369 foreach my $thisframework (keys %$frameworks) {
370 my $selected = 1 if $thisframework eq $frameworkcode;
371 my %row =(
372 value => $thisframework,
373 selected => $selected,
374 description => $frameworks->{$thisframework}->{'frameworktext'},
376 push @frameworksloop, \%row;
378 $template->param(frameworkloop => \@frameworksloop);
380 =head3 in TEMPLATE
382 <form action="[% script_name %] method=post>
383 <select name="frameworkcode">
384 <option value="">Default</option>
385 [% FOREACH framework IN frameworkloop %]
386 [% IF ( framework.selected ) %]
387 <option value="[% framework.value %]" selected="selected">[% framework.description %]</option>
388 [% ELSE %]
389 <option value="[% framework.value %]">[% framework.description %]</option>
390 [% END %]
391 [% END %]
392 </select>
393 <input type=text name=searchfield value="[% searchfield %]">
394 <input type="submit" value="OK" class="button">
395 </form>
397 =cut
399 sub getframeworks {
401 # returns a reference to a hash of references to branches...
402 my %itemtypes;
403 my $dbh = C4::Context->dbh;
404 my $sth = $dbh->prepare("select * from biblio_framework");
405 $sth->execute;
406 while ( my $IT = $sth->fetchrow_hashref ) {
407 $itemtypes{ $IT->{'frameworkcode'} } = $IT;
409 return ( \%itemtypes );
412 =head2 GetFrameworksLoop
414 $frameworks = GetFrameworksLoop( $frameworkcode );
416 Returns the loop suggested on getframework(), but ordered by framework description.
418 build a HTML select with the following code :
420 =head3 in PERL SCRIPT
422 $template->param( frameworkloop => GetFrameworksLoop( $frameworkcode ) );
424 =head3 in TEMPLATE
426 Same as getframework()
428 <form action="[% script_name %] method=post>
429 <select name="frameworkcode">
430 <option value="">Default</option>
431 [% FOREACH framework IN frameworkloop %]
432 [% IF ( framework.selected ) %]
433 <option value="[% framework.value %]" selected="selected">[% framework.description %]</option>
434 [% ELSE %]
435 <option value="[% framework.value %]">[% framework.description %]</option>
436 [% END %]
437 [% END %]
438 </select>
439 <input type=text name=searchfield value="[% searchfield %]">
440 <input type="submit" value="OK" class="button">
441 </form>
443 =cut
445 sub GetFrameworksLoop {
446 my $frameworkcode = shift;
447 my $frameworks = getframeworks();
448 my @frameworkloop;
449 foreach my $thisframework (sort { uc($frameworks->{$a}->{'frameworktext'}) cmp uc($frameworks->{$b}->{'frameworktext'}) } keys %$frameworks) {
450 my $selected = ( $thisframework eq $frameworkcode ) ? 1 : undef;
451 my %row = (
452 value => $thisframework,
453 selected => $selected,
454 description => $frameworks->{$thisframework}->{'frameworktext'},
456 push @frameworkloop, \%row;
458 return \@frameworkloop;
461 =head2 getframeworkinfo
463 $frameworkinfo = &getframeworkinfo($frameworkcode);
465 Returns information about an frameworkcode.
467 =cut
469 sub getframeworkinfo {
470 my ($frameworkcode) = @_;
471 my $dbh = C4::Context->dbh;
472 my $sth =
473 $dbh->prepare("select * from biblio_framework where frameworkcode=?");
474 $sth->execute($frameworkcode);
475 my $res = $sth->fetchrow_hashref;
476 return $res;
479 =head2 getitemtypeinfo
481 $itemtype = &getitemtypeinfo($itemtype, [$interface]);
483 Returns information about an itemtype. The optional $interface argument
484 sets which interface ('opac' or 'intranet') to return the imageurl for.
485 Defaults to intranet.
487 =cut
489 sub getitemtypeinfo {
490 my ($itemtype, $interface) = @_;
491 my $dbh = C4::Context->dbh;
492 my $sth = $dbh->prepare("select * from itemtypes where itemtype=?");
493 $sth->execute($itemtype);
494 my $res = $sth->fetchrow_hashref;
496 $res->{imageurl} = getitemtypeimagelocation( ( ( defined $interface && $interface eq 'opac' ) ? 'opac' : 'intranet' ), $res->{imageurl} );
498 return $res;
501 =head2 getitemtypeimagedir
503 my $directory = getitemtypeimagedir( 'opac' );
505 pass in 'opac' or 'intranet'. Defaults to 'opac'.
507 returns the full path to the appropriate directory containing images.
509 =cut
511 sub getitemtypeimagedir {
512 my $src = shift || 'opac';
513 if ($src eq 'intranet') {
514 return C4::Context->config('intrahtdocs') . '/' .C4::Context->preference('template') . '/img/itemtypeimg';
515 } else {
516 return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
520 sub getitemtypeimagesrc {
521 my $src = shift || 'opac';
522 if ($src eq 'intranet') {
523 return '/intranet-tmpl' . '/' . C4::Context->preference('template') . '/img/itemtypeimg';
524 } else {
525 return '/opac-tmpl' . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
529 sub getitemtypeimagelocation {
530 my ( $src, $image ) = @_;
532 return '' if ( !$image );
533 require URI::Split;
535 my $scheme = ( URI::Split::uri_split( $image ) )[0];
537 return $image if ( $scheme );
539 return getitemtypeimagesrc( $src ) . '/' . $image;
542 =head3 _getImagesFromDirectory
544 Find all of the image files in a directory in the filesystem
546 parameters: a directory name
548 returns: a list of images in that directory.
550 Notes: this does not traverse into subdirectories. See
551 _getSubdirectoryNames for help with that.
552 Images are assumed to be files with .gif or .png file extensions.
553 The image names returned do not have the directory name on them.
555 =cut
557 sub _getImagesFromDirectory {
558 my $directoryname = shift;
559 return unless defined $directoryname;
560 return unless -d $directoryname;
562 if ( opendir ( my $dh, $directoryname ) ) {
563 my @images = grep { /\.(gif|png)$/i } readdir( $dh );
564 closedir $dh;
565 @images = sort(@images);
566 return @images;
567 } else {
568 warn "unable to opendir $directoryname: $!";
569 return;
573 =head3 _getSubdirectoryNames
575 Find all of the directories in a directory in the filesystem
577 parameters: a directory name
579 returns: a list of subdirectories in that directory.
581 Notes: this does not traverse into subdirectories. Only the first
582 level of subdirectories are returned.
583 The directory names returned don't have the parent directory name on them.
585 =cut
587 sub _getSubdirectoryNames {
588 my $directoryname = shift;
589 return unless defined $directoryname;
590 return unless -d $directoryname;
592 if ( opendir ( my $dh, $directoryname ) ) {
593 my @directories = grep { -d File::Spec->catfile( $directoryname, $_ ) && ! ( /^\./ ) } readdir( $dh );
594 closedir $dh;
595 return @directories;
596 } else {
597 warn "unable to opendir $directoryname: $!";
598 return;
602 =head3 getImageSets
604 returns: a listref of hashrefs. Each hash represents another collection of images.
606 { imagesetname => 'npl', # the name of the image set (npl is the original one)
607 images => listref of image hashrefs
610 each image is represented by a hashref like this:
612 { KohaImage => 'npl/image.gif',
613 StaffImageUrl => '/intranet-tmpl/prog/img/itemtypeimg/npl/image.gif',
614 OpacImageURL => '/opac-tmpl/prog/itemtypeimg/npl/image.gif'
615 checked => 0 or 1: was this the image passed to this method?
616 Note: I'd like to remove this somehow.
619 =cut
621 sub getImageSets {
622 my %params = @_;
623 my $checked = $params{'checked'} || '';
625 my $paths = { staff => { filesystem => getitemtypeimagedir('intranet'),
626 url => getitemtypeimagesrc('intranet'),
628 opac => { filesystem => getitemtypeimagedir('opac'),
629 url => getitemtypeimagesrc('opac'),
633 my @imagesets = (); # list of hasrefs of image set data to pass to template
634 my @subdirectories = _getSubdirectoryNames( $paths->{'staff'}{'filesystem'} );
635 foreach my $imagesubdir ( @subdirectories ) {
636 warn $imagesubdir if $DEBUG;
637 my @imagelist = (); # hashrefs of image info
638 my @imagenames = _getImagesFromDirectory( File::Spec->catfile( $paths->{'staff'}{'filesystem'}, $imagesubdir ) );
639 my $imagesetactive = 0;
640 foreach my $thisimage ( @imagenames ) {
641 push( @imagelist,
642 { KohaImage => "$imagesubdir/$thisimage",
643 StaffImageUrl => join( '/', $paths->{'staff'}{'url'}, $imagesubdir, $thisimage ),
644 OpacImageUrl => join( '/', $paths->{'opac'}{'url'}, $imagesubdir, $thisimage ),
645 checked => "$imagesubdir/$thisimage" eq $checked ? 1 : 0,
648 $imagesetactive = 1 if "$imagesubdir/$thisimage" eq $checked;
650 push @imagesets, { imagesetname => $imagesubdir,
651 imagesetactive => $imagesetactive,
652 images => \@imagelist };
655 return \@imagesets;
658 =head2 GetPrinters
660 $printers = &GetPrinters();
661 @queues = keys %$printers;
663 Returns information about existing printer queues.
665 C<$printers> is a reference-to-hash whose keys are the print queues
666 defined in the printers table of the Koha database. The values are
667 references-to-hash, whose keys are the fields in the printers table.
669 =cut
671 sub GetPrinters {
672 my %printers;
673 my $dbh = C4::Context->dbh;
674 my $sth = $dbh->prepare("select * from printers");
675 $sth->execute;
676 while ( my $printer = $sth->fetchrow_hashref ) {
677 $printers{ $printer->{'printqueue'} } = $printer;
679 return ( \%printers );
682 =head2 GetPrinter
684 $printer = GetPrinter( $query, $printers );
686 =cut
688 sub GetPrinter {
689 my ( $query, $printers ) = @_; # get printer for this query from printers
690 my $printer = $query->param('printer');
691 my %cookie = $query->cookie('userenv');
692 ($printer) || ( $printer = $cookie{'printer'} ) || ( $printer = '' );
693 ( $printers->{$printer} ) || ( $printer = ( keys %$printers )[0] );
694 return $printer;
697 =head2 getnbpages
699 Returns the number of pages to display in a pagination bar, given the number
700 of items and the number of items per page.
702 =cut
704 sub getnbpages {
705 my ( $nb_items, $nb_items_per_page ) = @_;
707 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
710 =head2 getallthemes
712 (@themes) = &getallthemes('opac');
713 (@themes) = &getallthemes('intranet');
715 Returns an array of all available themes.
717 =cut
719 sub getallthemes {
720 my $type = shift;
721 my $htdocs;
722 my @themes;
723 if ( $type eq 'intranet' ) {
724 $htdocs = C4::Context->config('intrahtdocs');
726 else {
727 $htdocs = C4::Context->config('opachtdocs');
729 opendir D, "$htdocs";
730 my @dirlist = readdir D;
731 foreach my $directory (@dirlist) {
732 next if $directory eq 'lib';
733 -d "$htdocs/$directory/en" and push @themes, $directory;
735 return @themes;
738 sub getFacets {
739 my $facets;
740 if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
741 $facets = [
743 idx => 'su-to',
744 label => 'Topics',
745 tags => [ qw/ 600ab 601ab 602a 604at 605a 606ax 610a / ],
746 sep => ' - ',
749 idx => 'su-geo',
750 label => 'Places',
751 tags => [ qw/ 607a / ],
752 sep => ' - ',
755 idx => 'su-ut',
756 label => 'Titles',
757 tags => [ qw/ 500a 501a 503a / ],
758 sep => ', ',
761 idx => 'au',
762 label => 'Authors',
763 tags => [ qw/ 700ab 701ab 702ab / ],
764 sep => C4::Context->preference("UNIMARCAuthorsFacetsSeparator"),
767 idx => 'se',
768 label => 'Series',
769 tags => [ qw/ 225a / ],
770 sep => ', ',
773 idx => 'location',
774 label => 'Location',
775 tags => [ qw/ 995e / ],
779 unless ( C4::Context->preference("singleBranchMode")
780 || GetBranchesCount() == 1 )
782 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
783 if ( $DisplayLibraryFacets eq 'both'
784 || $DisplayLibraryFacets eq 'holding' )
786 push(
787 @$facets,
789 idx => 'holdingbranch',
790 label => 'HoldingLibrary',
791 tags => [qw / 995b /],
796 if ( $DisplayLibraryFacets eq 'both'
797 || $DisplayLibraryFacets eq 'home' )
799 push(
800 @$facets,
802 idx => 'homebranch',
803 label => 'HomeLibrary',
804 tags => [qw / 995a /],
810 else {
811 $facets = [
813 idx => 'su-to',
814 label => 'Topics',
815 tags => [ qw/ 650a / ],
816 sep => '--',
819 # idx => 'su-na',
820 # label => 'People and Organizations',
821 # tags => [ qw/ 600a 610a 611a / ],
822 # sep => 'a',
823 # },
825 idx => 'su-geo',
826 label => 'Places',
827 tags => [ qw/ 651a / ],
828 sep => '--',
831 idx => 'su-ut',
832 label => 'Titles',
833 tags => [ qw/ 630a / ],
834 sep => '--',
837 idx => 'au',
838 label => 'Authors',
839 tags => [ qw/ 100a 110a 700a / ],
840 sep => ', ',
843 idx => 'se',
844 label => 'Series',
845 tags => [ qw/ 440a 490a / ],
846 sep => ', ',
849 idx => 'itype',
850 label => 'ItemTypes',
851 tags => [ qw/ 952y 942c / ],
852 sep => ', ',
855 idx => 'location',
856 label => 'Location',
857 tags => [ qw / 952c / ],
861 unless ( C4::Context->preference("singleBranchMode")
862 || GetBranchesCount() == 1 )
864 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
865 if ( $DisplayLibraryFacets eq 'both'
866 || $DisplayLibraryFacets eq 'holding' )
868 push(
869 @$facets,
871 idx => 'holdingbranch',
872 label => 'HoldingLibrary',
873 tags => [qw / 952b /],
878 if ( $DisplayLibraryFacets eq 'both'
879 || $DisplayLibraryFacets eq 'home' )
881 push(
882 @$facets,
884 idx => 'homebranch',
885 label => 'HomeLibrary',
886 tags => [qw / 952a /],
892 return $facets;
895 =head2 get_infos_of
897 Return a href where a key is associated to a href. You give a query,
898 the name of the key among the fields returned by the query. If you
899 also give as third argument the name of the value, the function
900 returns a href of scalar. The optional 4th argument is an arrayref of
901 items passed to the C<execute()> call. It is designed to bind
902 parameters to any placeholders in your SQL.
904 my $query = '
905 SELECT itemnumber,
906 notforloan,
907 barcode
908 FROM items
911 # generic href of any information on the item, href of href.
912 my $iteminfos_of = get_infos_of($query, 'itemnumber');
913 print $iteminfos_of->{$itemnumber}{barcode};
915 # specific information, href of scalar
916 my $barcode_of_item = get_infos_of($query, 'itemnumber', 'barcode');
917 print $barcode_of_item->{$itemnumber};
919 =cut
921 sub get_infos_of {
922 my ( $query, $key_name, $value_name, $bind_params ) = @_;
924 my $dbh = C4::Context->dbh;
926 my $sth = $dbh->prepare($query);
927 $sth->execute( @$bind_params );
929 my %infos_of;
930 while ( my $row = $sth->fetchrow_hashref ) {
931 if ( defined $value_name ) {
932 $infos_of{ $row->{$key_name} } = $row->{$value_name};
934 else {
935 $infos_of{ $row->{$key_name} } = $row;
938 $sth->finish;
940 return \%infos_of;
943 =head2 get_notforloan_label_of
945 my $notforloan_label_of = get_notforloan_label_of();
947 Each authorised value of notforloan (information available in items and
948 itemtypes) is link to a single label.
950 Returns a href where keys are authorised values and values are corresponding
951 labels.
953 foreach my $authorised_value (keys %{$notforloan_label_of}) {
954 printf(
955 "authorised_value: %s => %s\n",
956 $authorised_value,
957 $notforloan_label_of->{$authorised_value}
961 =cut
963 # FIXME - why not use GetAuthorisedValues ??
965 sub get_notforloan_label_of {
966 my $dbh = C4::Context->dbh;
968 my $query = '
969 SELECT authorised_value
970 FROM marc_subfield_structure
971 WHERE kohafield = \'items.notforloan\'
972 LIMIT 0, 1
974 my $sth = $dbh->prepare($query);
975 $sth->execute();
976 my ($statuscode) = $sth->fetchrow_array();
978 $query = '
979 SELECT lib,
980 authorised_value
981 FROM authorised_values
982 WHERE category = ?
984 $sth = $dbh->prepare($query);
985 $sth->execute($statuscode);
986 my %notforloan_label_of;
987 while ( my $row = $sth->fetchrow_hashref ) {
988 $notforloan_label_of{ $row->{authorised_value} } = $row->{lib};
990 $sth->finish;
992 return \%notforloan_label_of;
995 =head2 displayServers
997 my $servers = displayServers();
998 my $servers = displayServers( $position );
999 my $servers = displayServers( $position, $type );
1001 displayServers returns a listref of hashrefs, each containing
1002 information about available z3950 servers. Each hashref has a format
1003 like:
1006 'checked' => 'checked',
1007 'encoding' => 'utf8',
1008 'icon' => undef,
1009 'id' => 'LIBRARY OF CONGRESS',
1010 'label' => '',
1011 'name' => 'server',
1012 'opensearch' => '',
1013 'value' => 'lx2.loc.gov:210/',
1014 'zed' => 1,
1017 =cut
1019 sub displayServers {
1020 my ( $position, $type ) = @_;
1021 my $dbh = C4::Context->dbh;
1023 my $strsth = 'SELECT * FROM z3950servers';
1024 my @where_clauses;
1025 my @bind_params;
1027 if ($position) {
1028 push @bind_params, $position;
1029 push @where_clauses, ' position = ? ';
1032 if ($type) {
1033 push @bind_params, $type;
1034 push @where_clauses, ' type = ? ';
1037 # reassemble where clause from where clause pieces
1038 if (@where_clauses) {
1039 $strsth .= ' WHERE ' . join( ' AND ', @where_clauses );
1042 my $rq = $dbh->prepare($strsth);
1043 $rq->execute(@bind_params);
1044 my @primaryserverloop;
1046 while ( my $data = $rq->fetchrow_hashref ) {
1047 push @primaryserverloop,
1048 { label => $data->{description},
1049 id => $data->{name},
1050 name => "server",
1051 value => $data->{host} . ":" . $data->{port} . "/" . $data->{database},
1052 encoding => ( $data->{encoding} ? $data->{encoding} : "iso-5426" ),
1053 checked => "checked",
1054 icon => $data->{icon},
1055 zed => $data->{type} eq 'zed',
1056 opensearch => $data->{type} eq 'opensearch'
1059 return \@primaryserverloop;
1063 =head2 GetKohaImageurlFromAuthorisedValues
1065 $authhorised_value = GetKohaImageurlFromAuthorisedValues( $category, $authvalcode );
1067 Return the first url of the authorised value image represented by $lib.
1069 =cut
1071 sub GetKohaImageurlFromAuthorisedValues {
1072 my ( $category, $lib ) = @_;
1073 my $dbh = C4::Context->dbh;
1074 my $sth = $dbh->prepare("SELECT imageurl FROM authorised_values WHERE category=? AND lib =?");
1075 $sth->execute( $category, $lib );
1076 while ( my $data = $sth->fetchrow_hashref ) {
1077 return $data->{'imageurl'};
1081 =head2 GetAuthValCode
1083 $authvalcode = GetAuthValCode($kohafield,$frameworkcode);
1085 =cut
1087 sub GetAuthValCode {
1088 my ($kohafield,$fwcode) = @_;
1089 my $dbh = C4::Context->dbh;
1090 $fwcode='' unless $fwcode;
1091 my $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield=? and frameworkcode=?');
1092 $sth->execute($kohafield,$fwcode);
1093 my ($authvalcode) = $sth->fetchrow_array;
1094 return $authvalcode;
1097 =head2 GetAuthValCodeFromField
1099 $authvalcode = GetAuthValCodeFromField($field,$subfield,$frameworkcode);
1101 C<$subfield> can be undefined
1103 =cut
1105 sub GetAuthValCodeFromField {
1106 my ($field,$subfield,$fwcode) = @_;
1107 my $dbh = C4::Context->dbh;
1108 $fwcode='' unless $fwcode;
1109 my $sth;
1110 if (defined $subfield) {
1111 $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?');
1112 $sth->execute($field,$subfield,$fwcode);
1113 } else {
1114 $sth = $dbh->prepare('select authorised_value from marc_tag_structure where tagfield=? and frameworkcode=?');
1115 $sth->execute($field,$fwcode);
1117 my ($authvalcode) = $sth->fetchrow_array;
1118 return $authvalcode;
1121 =head2 GetAuthorisedValues
1123 $authvalues = GetAuthorisedValues([$category], [$selected]);
1125 This function returns all authorised values from the'authorised_value' table in a reference to array of hashrefs.
1127 C<$category> returns authorised values for just one category (optional).
1129 C<$opac> If set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1131 =cut
1133 sub GetAuthorisedValues {
1134 my ( $category, $selected, $opac ) = @_;
1135 my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
1136 my @results;
1137 my $dbh = C4::Context->dbh;
1138 my $query = qq{
1139 SELECT *
1140 FROM authorised_values
1142 $query .= qq{
1143 LEFT JOIN authorised_values_branches ON ( id = av_id )
1144 } if $branch_limit;
1145 my @where_strings;
1146 my @where_args;
1147 if($category) {
1148 push @where_strings, "category = ?";
1149 push @where_args, $category;
1151 if($branch_limit) {
1152 push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
1153 push @where_args, $branch_limit;
1155 if(@where_strings > 0) {
1156 $query .= " WHERE " . join(" AND ", @where_strings);
1158 $query .= " GROUP BY lib";
1159 $query .= ' ORDER BY category, ' . (
1160 $opac ? 'COALESCE(lib_opac, lib)'
1161 : 'lib, lib_opac'
1164 my $sth = $dbh->prepare($query);
1166 $sth->execute( @where_args );
1167 while (my $data=$sth->fetchrow_hashref) {
1168 if ( defined $selected and $selected eq $data->{authorised_value} ) {
1169 $data->{selected} = 1;
1171 else {
1172 $data->{selected} = 0;
1175 if ($opac && $data->{lib_opac}) {
1176 $data->{lib} = $data->{lib_opac};
1178 push @results, $data;
1180 $sth->finish;
1181 return \@results;
1184 =head2 GetAuthorisedValueCategories
1186 $auth_categories = GetAuthorisedValueCategories();
1188 Return an arrayref of all of the available authorised
1189 value categories.
1191 =cut
1193 sub GetAuthorisedValueCategories {
1194 my $dbh = C4::Context->dbh;
1195 my $sth = $dbh->prepare("SELECT DISTINCT category FROM authorised_values ORDER BY category");
1196 $sth->execute;
1197 my @results;
1198 while (defined (my $category = $sth->fetchrow_array) ) {
1199 push @results, $category;
1201 return \@results;
1204 =head2 IsAuthorisedValueCategory
1206 $is_auth_val_category = IsAuthorisedValueCategory($category);
1208 Returns whether a given category name is a valid one
1210 =cut
1212 sub IsAuthorisedValueCategory {
1213 my $category = shift;
1214 my $query = '
1215 SELECT category
1216 FROM authorised_values
1217 WHERE BINARY category=?
1218 LIMIT 1
1220 my $sth = C4::Context->dbh->prepare($query);
1221 $sth->execute($category);
1222 $sth->fetchrow ? return 1
1223 : return 0;
1226 =head2 GetAuthorisedValueByCode
1228 $authorised_value = GetAuthorisedValueByCode( $category, $authvalcode, $opac );
1230 Return the lib attribute from authorised_values from the row identified
1231 by the passed category and code
1233 =cut
1235 sub GetAuthorisedValueByCode {
1236 my ( $category, $authvalcode, $opac ) = @_;
1238 my $field = $opac ? 'lib_opac' : 'lib';
1239 my $dbh = C4::Context->dbh;
1240 my $sth = $dbh->prepare("SELECT $field FROM authorised_values WHERE category=? AND authorised_value =?");
1241 $sth->execute( $category, $authvalcode );
1242 while ( my $data = $sth->fetchrow_hashref ) {
1243 return $data->{ $field };
1247 =head2 GetKohaAuthorisedValues
1249 Takes $kohafield, $fwcode as parameters.
1251 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1253 Returns hashref of Code => description
1255 Returns undef if no authorised value category is defined for the kohafield.
1257 =cut
1259 sub GetKohaAuthorisedValues {
1260 my ($kohafield,$fwcode,$opac) = @_;
1261 $fwcode='' unless $fwcode;
1262 my %values;
1263 my $dbh = C4::Context->dbh;
1264 my $avcode = GetAuthValCode($kohafield,$fwcode);
1265 if ($avcode) {
1266 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1267 $sth->execute($avcode);
1268 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1269 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1271 return \%values;
1272 } else {
1273 return;
1277 =head2 GetKohaAuthorisedValuesFromField
1279 Takes $field, $subfield, $fwcode as parameters.
1281 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1282 $subfield can be undefined
1284 Returns hashref of Code => description
1286 Returns undef if no authorised value category is defined for the given field and subfield
1288 =cut
1290 sub GetKohaAuthorisedValuesFromField {
1291 my ($field, $subfield, $fwcode,$opac) = @_;
1292 $fwcode='' unless $fwcode;
1293 my %values;
1294 my $dbh = C4::Context->dbh;
1295 my $avcode = GetAuthValCodeFromField($field, $subfield, $fwcode);
1296 if ($avcode) {
1297 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1298 $sth->execute($avcode);
1299 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1300 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1302 return \%values;
1303 } else {
1304 return;
1308 =head2 xml_escape
1310 my $escaped_string = C4::Koha::xml_escape($string);
1312 Convert &, <, >, ', and " in a string to XML entities
1314 =cut
1316 sub xml_escape {
1317 my $str = shift;
1318 return '' unless defined $str;
1319 $str =~ s/&/&amp;/g;
1320 $str =~ s/</&lt;/g;
1321 $str =~ s/>/&gt;/g;
1322 $str =~ s/'/&apos;/g;
1323 $str =~ s/"/&quot;/g;
1324 return $str;
1327 =head2 GetKohaAuthorisedValueLib
1329 Takes $category, $authorised_value as parameters.
1331 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1333 Returns authorised value description
1335 =cut
1337 sub GetKohaAuthorisedValueLib {
1338 my ($category,$authorised_value,$opac) = @_;
1339 my $value;
1340 my $dbh = C4::Context->dbh;
1341 my $sth = $dbh->prepare("select lib, lib_opac from authorised_values where category=? and authorised_value=?");
1342 $sth->execute($category,$authorised_value);
1343 my $data = $sth->fetchrow_hashref;
1344 $value = ($opac && $$data{'lib_opac'}) ? $$data{'lib_opac'} : $$data{'lib'};
1345 return $value;
1348 =head2 AddAuthorisedValue
1350 AddAuthorisedValue($category, $authorised_value, $lib, $lib_opac, $imageurl);
1352 Create a new authorised value.
1354 =cut
1356 sub AddAuthorisedValue {
1357 my ($category, $authorised_value, $lib, $lib_opac, $imageurl) = @_;
1359 my $dbh = C4::Context->dbh;
1360 my $query = qq{
1361 INSERT INTO authorised_values (category, authorised_value, lib, lib_opac, imageurl)
1362 VALUES (?,?,?,?,?)
1364 my $sth = $dbh->prepare($query);
1365 $sth->execute($category, $authorised_value, $lib, $lib_opac, $imageurl);
1368 =head2 display_marc_indicators
1370 my $display_form = C4::Koha::display_marc_indicators($field);
1372 C<$field> is a MARC::Field object
1374 Generate a display form of the indicators of a variable
1375 MARC field, replacing any blanks with '#'.
1377 =cut
1379 sub display_marc_indicators {
1380 my $field = shift;
1381 my $indicators = '';
1382 if ($field->tag() >= 10) {
1383 $indicators = $field->indicator(1) . $field->indicator(2);
1384 $indicators =~ s/ /#/g;
1386 return $indicators;
1389 sub GetNormalizedUPC {
1390 my ($record,$marcflavour) = @_;
1391 my (@fields,$upc);
1393 if ($marcflavour eq 'UNIMARC') {
1394 @fields = $record->field('072');
1395 foreach my $field (@fields) {
1396 my $upc = _normalize_match_point($field->subfield('a'));
1397 if ($upc ne '') {
1398 return $upc;
1403 else { # assume marc21 if not unimarc
1404 @fields = $record->field('024');
1405 foreach my $field (@fields) {
1406 my $indicator = $field->indicator(1);
1407 my $upc = _normalize_match_point($field->subfield('a'));
1408 if ($indicator == 1 and $upc ne '') {
1409 return $upc;
1415 # Normalizes and returns the first valid ISBN found in the record
1416 # ISBN13 are converted into ISBN10. This is required to get some book cover images.
1417 sub GetNormalizedISBN {
1418 my ($isbn,$record,$marcflavour) = @_;
1419 my @fields;
1420 if ($isbn) {
1421 # Koha attempts to store multiple ISBNs in biblioitems.isbn, separated by " | "
1422 # anything after " | " should be removed, along with the delimiter
1423 $isbn =~ s/(.*)( \| )(.*)/$1/;
1424 return _isbn_cleanup($isbn);
1426 return unless $record;
1428 if ($marcflavour eq 'UNIMARC') {
1429 @fields = $record->field('010');
1430 foreach my $field (@fields) {
1431 my $isbn = $field->subfield('a');
1432 if ($isbn) {
1433 return _isbn_cleanup($isbn);
1434 } else {
1435 return;
1439 else { # assume marc21 if not unimarc
1440 @fields = $record->field('020');
1441 foreach my $field (@fields) {
1442 $isbn = $field->subfield('a');
1443 if ($isbn) {
1444 return _isbn_cleanup($isbn);
1445 } else {
1446 return;
1452 sub GetNormalizedEAN {
1453 my ($record,$marcflavour) = @_;
1454 my (@fields,$ean);
1456 if ($marcflavour eq 'UNIMARC') {
1457 @fields = $record->field('073');
1458 foreach my $field (@fields) {
1459 $ean = _normalize_match_point($field->subfield('a'));
1460 if ($ean ne '') {
1461 return $ean;
1465 else { # assume marc21 if not unimarc
1466 @fields = $record->field('024');
1467 foreach my $field (@fields) {
1468 my $indicator = $field->indicator(1);
1469 $ean = _normalize_match_point($field->subfield('a'));
1470 if ($indicator == 3 and $ean ne '') {
1471 return $ean;
1476 sub GetNormalizedOCLCNumber {
1477 my ($record,$marcflavour) = @_;
1478 my (@fields,$oclc);
1480 if ($marcflavour eq 'UNIMARC') {
1481 # TODO: add UNIMARC fields
1483 else { # assume marc21 if not unimarc
1484 @fields = $record->field('035');
1485 foreach my $field (@fields) {
1486 $oclc = $field->subfield('a');
1487 if ($oclc =~ /OCoLC/) {
1488 $oclc =~ s/\(OCoLC\)//;
1489 return $oclc;
1490 } else {
1491 return;
1497 sub GetAuthvalueDropbox {
1498 my ( $authcat, $default ) = @_;
1499 my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
1500 my $dbh = C4::Context->dbh;
1502 my $query = qq{
1503 SELECT *
1504 FROM authorised_values
1506 $query .= qq{
1507 LEFT JOIN authorised_values_branches ON ( id = av_id )
1508 } if $branch_limit;
1509 $query .= qq{
1510 WHERE category = ?
1512 $query .= " AND ( branchcode = ? OR branchcode IS NULL )" if $branch_limit;
1513 $query .= " GROUP BY lib ORDER BY category, lib, lib_opac";
1514 my $sth = $dbh->prepare($query);
1515 $sth->execute( $authcat, $branch_limit ? $branch_limit : () );
1518 my $option_list = [];
1519 my @authorised_values = ( q{} );
1520 while (my $av = $sth->fetchrow_hashref) {
1521 push @{$option_list}, {
1522 value => $av->{authorised_value},
1523 label => $av->{lib},
1524 default => ($default eq $av->{authorised_value}),
1528 if ( @{$option_list} ) {
1529 return $option_list;
1531 return;
1535 =head2 GetDailyQuote($opts)
1537 Takes a hashref of options
1539 Currently supported options are:
1541 'id' An exact quote id
1542 'random' Select a random quote
1543 noop When no option is passed in, this sub will return the quote timestamped for the current day
1545 The function returns an anonymous hash following this format:
1548 'source' => 'source-of-quote',
1549 'timestamp' => 'timestamp-value',
1550 'text' => 'text-of-quote',
1551 'id' => 'quote-id'
1554 =cut
1556 # This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
1557 # at least for default option
1559 sub GetDailyQuote {
1560 my %opts = @_;
1561 my $dbh = C4::Context->dbh;
1562 my $query = '';
1563 my $sth = undef;
1564 my $quote = undef;
1565 if ($opts{'id'}) {
1566 $query = 'SELECT * FROM quotes WHERE id = ?';
1567 $sth = $dbh->prepare($query);
1568 $sth->execute($opts{'id'});
1569 $quote = $sth->fetchrow_hashref();
1571 elsif ($opts{'random'}) {
1572 # Fall through... we also return a random quote as a catch-all if all else fails
1574 else {
1575 $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp DESC LIMIT 0,1';
1576 $sth = $dbh->prepare($query);
1577 $sth->execute();
1578 $quote = $sth->fetchrow_hashref();
1580 unless ($quote) { # if there are not matches, choose a random quote
1581 # get a list of all available quote ids
1582 $sth = C4::Context->dbh->prepare('SELECT count(*) FROM quotes;');
1583 $sth->execute;
1584 my $range = ($sth->fetchrow_array)[0];
1585 # chose a random id within that range if there is more than one quote
1586 my $offset = int(rand($range));
1587 # grab it
1588 $query = 'SELECT * FROM quotes ORDER BY id LIMIT 1 OFFSET ?';
1589 $sth = C4::Context->dbh->prepare($query);
1590 # see http://www.perlmonks.org/?node_id=837422 for why
1591 # we're being verbose and using bind_param
1592 $sth->bind_param(1, $offset, SQL_INTEGER);
1593 $sth->execute();
1594 $quote = $sth->fetchrow_hashref();
1595 # update the timestamp for that quote
1596 $query = 'UPDATE quotes SET timestamp = ? WHERE id = ?';
1597 $sth = C4::Context->dbh->prepare($query);
1598 $sth->execute(
1599 DateTime::Format::MySQL->format_datetime( dt_from_string() ),
1600 $quote->{'id'}
1603 return $quote;
1606 sub _normalize_match_point {
1607 my $match_point = shift;
1608 (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
1609 $normalized_match_point =~ s/-//g;
1611 return $normalized_match_point;
1614 sub _isbn_cleanup {
1615 my ($isbn) = @_;
1616 return NormalizeISBN(
1618 isbn => $isbn,
1619 format => 'ISBN-10',
1620 strip_hyphens => 1,
1622 ) if $isbn;
1625 =head2 NormalizedISBN
1627 my $isbns = NormalizedISBN({
1628 isbn => $isbn,
1629 strip_hyphens => [0,1],
1630 format => ['ISBN-10', 'ISBN-13']
1633 Returns an isbn validated by Business::ISBN.
1634 Optionally strips hyphens and/or forces the isbn
1635 to be of the specified format.
1637 If the string cannot be validated as an isbn,
1638 it returns nothing.
1640 =cut
1642 sub NormalizeISBN {
1643 my ($params) = @_;
1645 my $string = $params->{isbn};
1646 my $strip_hyphens = $params->{strip_hyphens};
1647 my $format = $params->{format};
1649 return unless $string;
1651 my $isbn = Business::ISBN->new($string);
1653 if ( $isbn && $isbn->is_valid() ) {
1655 if ( $format eq 'ISBN-10' ) {
1656 $isbn = $isbn->as_isbn10();
1658 elsif ( $format eq 'ISBN-13' ) {
1659 $isbn = $isbn->as_isbn13();
1662 if ($strip_hyphens) {
1663 $string = $isbn->as_string( [] );
1664 } else {
1665 $string = $isbn->as_string();
1668 return $string;
1672 =head2 GetVariationsOfISBN
1674 my @isbns = GetVariationsOfISBN( $isbn );
1676 Returns a list of varations of the given isbn in
1677 both ISBN-10 and ISBN-13 formats, with and without
1678 hyphens.
1680 In a scalar context, the isbns are returned as a
1681 string delimited by ' | '.
1683 =cut
1685 sub GetVariationsOfISBN {
1686 my ($isbn) = @_;
1688 return unless $isbn;
1690 my @isbns;
1692 push( @isbns, NormalizeISBN({ isbn => $isbn }) );
1693 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10' }) );
1694 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13' }) );
1695 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10', strip_hyphens => 1 }) );
1696 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13', strip_hyphens => 1 }) );
1698 # Strip out any "empty" strings from the array
1699 @isbns = grep { defined($_) && $_ =~ /\S/ } @isbns;
1701 return wantarray ? @isbns : join( " | ", @isbns );
1704 =head2 GetVariationsOfISBNs
1706 my @isbns = GetVariationsOfISBNs( @isbns );
1708 Returns a list of varations of the given isbns in
1709 both ISBN-10 and ISBN-13 formats, with and without
1710 hyphens.
1712 In a scalar context, the isbns are returned as a
1713 string delimited by ' | '.
1715 =cut
1717 sub GetVariationsOfISBNs {
1718 my (@isbns) = @_;
1720 @isbns = map { GetVariationsOfISBN( $_ ) } @isbns;
1722 return wantarray ? @isbns : join( " | ", @isbns );
1727 __END__
1729 =head1 AUTHOR
1731 Koha Team
1733 =cut