Bug 16011: $VERSION - Remove the $VERSION init
[koha.git] / C4 / Koha.pm
blob36e81dad192b63064c40f8d726ae449595c1a799
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
10 # under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
14 # Koha is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with Koha; if not, see <http://www.gnu.org/licenses>.
23 use strict;
24 #use warnings; FIXME - Bug 2505
26 use C4::Context;
27 use C4::Branch; # Can be removed?
28 use Koha::Cache;
29 use Koha::DateUtils qw(dt_from_string);
30 use Koha::Libraries;
31 use DateTime::Format::MySQL;
32 use Business::ISBN;
33 use autouse 'Data::cselectall_arrayref' => qw(Dumper);
34 use DBI qw(:sql_types);
35 use vars qw(@ISA @EXPORT @EXPORT_OK $DEBUG);
37 BEGIN {
38 require Exporter;
39 @ISA = qw(Exporter);
40 @EXPORT = qw(
41 &GetPrinters &GetPrinter
42 &GetItemTypes &getitemtypeinfo
43 &GetItemTypesCategorized &GetItemTypesByCategory
44 &GetSupportName &GetSupportList
45 &getframeworks &getframeworkinfo
46 &GetFrameworksLoop
47 &getallthemes
48 &getFacets
49 &getnbpages
50 &get_infos_of
51 &get_notforloan_label_of
52 &getitemtypeimagedir
53 &getitemtypeimagesrc
54 &getitemtypeimagelocation
55 &GetAuthorisedValues
56 &GetAuthorisedValueCategories
57 &GetKohaAuthorisedValues
58 &GetKohaAuthorisedValuesFromField
59 &GetKohaAuthorisedValuesMapping
60 &GetKohaAuthorisedValueLib
61 &GetAuthorisedValueByCode
62 &GetAuthValCode
63 &GetNormalizedUPC
64 &GetNormalizedISBN
65 &GetNormalizedEAN
66 &GetNormalizedOCLCNumber
67 &xml_escape
69 &GetVariationsOfISBN
70 &GetVariationsOfISBNs
71 &NormalizeISBN
73 $DEBUG
75 $DEBUG = 0;
76 @EXPORT_OK = qw( GetDailyQuote );
79 =head1 NAME
81 C4::Koha - Perl Module containing convenience functions for Koha scripts
83 =head1 SYNOPSIS
85 use C4::Koha;
87 =head1 DESCRIPTION
89 Koha.pm provides many functions for Koha scripts.
91 =head1 FUNCTIONS
93 =cut
95 =head2 GetSupportName
97 $itemtypename = &GetSupportName($codestring);
99 Returns a string with the name of the itemtype.
101 =cut
103 sub GetSupportName{
104 my ($codestring)=@_;
105 return if (! $codestring);
106 my $resultstring;
107 my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
108 if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') {
109 my $query = qq|
110 SELECT description
111 FROM itemtypes
112 WHERE itemtype=?
113 order by description
115 my $sth = C4::Context->dbh->prepare($query);
116 $sth->execute($codestring);
117 ($resultstring)=$sth->fetchrow;
118 return $resultstring;
119 } else {
120 my $sth =
121 C4::Context->dbh->prepare(
122 "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
124 $sth->execute( $advanced_search_types, $codestring );
125 my $data = $sth->fetchrow_hashref;
126 return $$data{'lib'};
130 =head2 GetSupportList
132 $itemtypes = &GetSupportList();
134 Returns an array ref containing informations about Support (since itemtype is rather a circulation code when item-level-itypes is used).
136 build a HTML select with the following code :
138 =head3 in PERL SCRIPT
140 my $itemtypes = GetSupportList();
141 $template->param(itemtypeloop => $itemtypes);
143 =head3 in TEMPLATE
145 <select name="itemtype" id="itemtype">
146 <option value=""></option>
147 [% FOREACH itemtypeloo IN itemtypeloop %]
148 [% IF ( itemtypeloo.selected ) %]
149 <option value="[% itemtypeloo.itemtype %]" selected="selected">[% itemtypeloo.description %]</option>
150 [% ELSE %]
151 <option value="[% itemtypeloo.itemtype %]">[% itemtypeloo.description %]</option>
152 [% END %]
153 [% END %]
154 </select>
156 =cut
158 sub GetSupportList{
159 my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
160 if (!$advanced_search_types or $advanced_search_types =~ /itemtypes/) {
161 return GetItemTypes( style => 'array' );
162 } else {
163 my $advsearchtypes = GetAuthorisedValues($advanced_search_types);
164 my @results= map {{itemtype=>$$_{authorised_value},description=>$$_{lib},imageurl=>$$_{imageurl}}} @$advsearchtypes;
165 return \@results;
168 =head2 GetItemTypes
170 $itemtypes = &GetItemTypes( style => $style );
172 Returns information about existing itemtypes.
174 Params:
175 style: either 'array' or 'hash', defaults to 'hash'.
176 'array' returns an arrayref,
177 'hash' return a hashref with the itemtype value as the key
179 build a HTML select with the following code :
181 =head3 in PERL SCRIPT
183 my $itemtypes = GetItemTypes;
184 my @itemtypesloop;
185 foreach my $thisitemtype (sort keys %$itemtypes) {
186 my $selected = 1 if $thisitemtype eq $itemtype;
187 my %row =(value => $thisitemtype,
188 selected => $selected,
189 description => $itemtypes->{$thisitemtype}->{'description'},
191 push @itemtypesloop, \%row;
193 $template->param(itemtypeloop => \@itemtypesloop);
195 =head3 in TEMPLATE
197 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
198 <select name="itemtype">
199 <option value="">Default</option>
200 <!-- TMPL_LOOP name="itemtypeloop" -->
201 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="description" --></option>
202 <!-- /TMPL_LOOP -->
203 </select>
204 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
205 <input type="submit" value="OK" class="button">
206 </form>
208 =cut
210 sub GetItemTypes {
211 my ( %params ) = @_;
212 my $style = defined( $params{'style'} ) ? $params{'style'} : 'hash';
214 require C4::Languages;
215 my $language = C4::Languages::getlanguage();
216 # returns a reference to a hash of references to itemtypes...
217 my $dbh = C4::Context->dbh;
218 my $query = q|
219 SELECT
220 itemtypes.itemtype,
221 itemtypes.description,
222 itemtypes.rentalcharge,
223 itemtypes.notforloan,
224 itemtypes.imageurl,
225 itemtypes.summary,
226 itemtypes.checkinmsg,
227 itemtypes.checkinmsgtype,
228 itemtypes.sip_media_type,
229 itemtypes.hideinopac,
230 itemtypes.searchcategory,
231 COALESCE( localization.translation, itemtypes.description ) AS translated_description
232 FROM itemtypes
233 LEFT JOIN localization ON itemtypes.itemtype = localization.code
234 AND localization.entity = 'itemtypes'
235 AND localization.lang = ?
236 ORDER BY itemtype
238 my $sth = $dbh->prepare($query);
239 $sth->execute( $language );
241 if ( $style eq 'hash' ) {
242 my %itemtypes;
243 while ( my $IT = $sth->fetchrow_hashref ) {
244 $itemtypes{ $IT->{'itemtype'} } = $IT;
246 return ( \%itemtypes );
247 } else {
248 return [ sort { lc $a->{translated_description} cmp lc $b->{translated_description} } @{ $sth->fetchall_arrayref( {} ) } ];
252 =head2 GetItemTypesCategorized
254 $categories = GetItemTypesCategorized();
256 Returns a hashref containing search categories.
257 A search category will be put in the hash if at least one of its itemtypes is visible in OPAC.
258 The categories must be part of Authorized Values (ITEMTYPECAT)
260 =cut
262 sub GetItemTypesCategorized {
263 my $dbh = C4::Context->dbh;
264 # Order is important, so that partially hidden (some items are not visible in OPAC) search
265 # categories will be visible. hideinopac=0 must be last.
266 my $query = q|
267 SELECT itemtype, description, imageurl, hideinopac, 0 as 'iscat' FROM itemtypes WHERE ISNULL(searchcategory) or length(searchcategory) = 0
268 UNION
269 SELECT DISTINCT searchcategory AS `itemtype`,
270 authorised_values.lib_opac AS description,
271 authorised_values.imageurl AS imageurl,
272 hideinopac, 1 as 'iscat'
273 FROM itemtypes
274 LEFT JOIN authorised_values ON searchcategory = authorised_value
275 WHERE searchcategory > '' and hideinopac=1
276 UNION
277 SELECT DISTINCT searchcategory AS `itemtype`,
278 authorised_values.lib_opac AS description,
279 authorised_values.imageurl AS imageurl,
280 hideinopac, 1 as 'iscat'
281 FROM itemtypes
282 LEFT JOIN authorised_values ON searchcategory = authorised_value
283 WHERE searchcategory > '' and hideinopac=0
285 return ($dbh->selectall_hashref($query,'itemtype'));
288 =head2 GetItemTypesByCategory
290 @results = GetItemTypesByCategory( $searchcategory );
292 Returns the itemtype code of all itemtypes included in a searchcategory.
294 =cut
296 sub GetItemTypesByCategory {
297 my ($category) = @_;
298 my $count = 0;
299 my @results;
300 my $dbh = C4::Context->dbh;
301 my $query = qq|SELECT itemtype FROM itemtypes WHERE searchcategory=?|;
302 my $tmp=$dbh->selectcol_arrayref($query,undef,$category);
303 return @$tmp;
306 =head2 getframework
308 $frameworks = &getframework();
310 Returns information about existing frameworks
312 build a HTML select with the following code :
314 =head3 in PERL SCRIPT
316 my $frameworks = getframeworks();
317 my @frameworkloop;
318 foreach my $thisframework (keys %$frameworks) {
319 my $selected = 1 if $thisframework eq $frameworkcode;
320 my %row =(
321 value => $thisframework,
322 selected => $selected,
323 description => $frameworks->{$thisframework}->{'frameworktext'},
325 push @frameworksloop, \%row;
327 $template->param(frameworkloop => \@frameworksloop);
329 =head3 in TEMPLATE
331 <form action="[% script_name %] method=post>
332 <select name="frameworkcode">
333 <option value="">Default</option>
334 [% FOREACH framework IN frameworkloop %]
335 [% IF ( framework.selected ) %]
336 <option value="[% framework.value %]" selected="selected">[% framework.description %]</option>
337 [% ELSE %]
338 <option value="[% framework.value %]">[% framework.description %]</option>
339 [% END %]
340 [% END %]
341 </select>
342 <input type=text name=searchfield value="[% searchfield %]">
343 <input type="submit" value="OK" class="button">
344 </form>
346 =cut
348 sub getframeworks {
350 # returns a reference to a hash of references to branches...
351 my %itemtypes;
352 my $dbh = C4::Context->dbh;
353 my $sth = $dbh->prepare("select * from biblio_framework");
354 $sth->execute;
355 while ( my $IT = $sth->fetchrow_hashref ) {
356 $itemtypes{ $IT->{'frameworkcode'} } = $IT;
358 return ( \%itemtypes );
361 =head2 GetFrameworksLoop
363 $frameworks = GetFrameworksLoop( $frameworkcode );
365 Returns the loop suggested on getframework(), but ordered by framework description.
367 build a HTML select with the following code :
369 =head3 in PERL SCRIPT
371 $template->param( frameworkloop => GetFrameworksLoop( $frameworkcode ) );
373 =head3 in TEMPLATE
375 Same as getframework()
377 <form action="[% script_name %] method=post>
378 <select name="frameworkcode">
379 <option value="">Default</option>
380 [% FOREACH framework IN frameworkloop %]
381 [% IF ( framework.selected ) %]
382 <option value="[% framework.value %]" selected="selected">[% framework.description %]</option>
383 [% ELSE %]
384 <option value="[% framework.value %]">[% framework.description %]</option>
385 [% END %]
386 [% END %]
387 </select>
388 <input type=text name=searchfield value="[% searchfield %]">
389 <input type="submit" value="OK" class="button">
390 </form>
392 =cut
394 sub GetFrameworksLoop {
395 my $frameworkcode = shift;
396 my $frameworks = getframeworks();
397 my @frameworkloop;
398 foreach my $thisframework (sort { uc($frameworks->{$a}->{'frameworktext'}) cmp uc($frameworks->{$b}->{'frameworktext'}) } keys %$frameworks) {
399 my $selected = ( $thisframework eq $frameworkcode ) ? 1 : undef;
400 my %row = (
401 value => $thisframework,
402 selected => $selected,
403 description => $frameworks->{$thisframework}->{'frameworktext'},
405 push @frameworkloop, \%row;
407 return \@frameworkloop;
410 =head2 getframeworkinfo
412 $frameworkinfo = &getframeworkinfo($frameworkcode);
414 Returns information about an frameworkcode.
416 =cut
418 sub getframeworkinfo {
419 my ($frameworkcode) = @_;
420 my $dbh = C4::Context->dbh;
421 my $sth =
422 $dbh->prepare("select * from biblio_framework where frameworkcode=?");
423 $sth->execute($frameworkcode);
424 my $res = $sth->fetchrow_hashref;
425 return $res;
428 =head2 getitemtypeinfo
430 $itemtype = &getitemtypeinfo($itemtype, [$interface]);
432 Returns information about an itemtype. The optional $interface argument
433 sets which interface ('opac' or 'intranet') to return the imageurl for.
434 Defaults to intranet.
436 =cut
438 sub getitemtypeinfo {
439 my ($itemtype, $interface) = @_;
440 my $dbh = C4::Context->dbh;
441 require C4::Languages;
442 my $language = C4::Languages::getlanguage();
443 my $it = $dbh->selectrow_hashref(q|
444 SELECT
445 itemtypes.itemtype,
446 itemtypes.description,
447 itemtypes.rentalcharge,
448 itemtypes.notforloan,
449 itemtypes.imageurl,
450 itemtypes.summary,
451 itemtypes.checkinmsg,
452 itemtypes.checkinmsgtype,
453 itemtypes.sip_media_type,
454 COALESCE( localization.translation, itemtypes.description ) AS translated_description
455 FROM itemtypes
456 LEFT JOIN localization ON itemtypes.itemtype = localization.code
457 AND localization.entity = 'itemtypes'
458 AND localization.lang = ?
459 WHERE itemtypes.itemtype = ?
460 |, undef, $language, $itemtype );
462 $it->{imageurl} = getitemtypeimagelocation( ( ( defined $interface && $interface eq 'opac' ) ? 'opac' : 'intranet' ), $it->{imageurl} );
464 return $it;
467 =head2 getitemtypeimagedir
469 my $directory = getitemtypeimagedir( 'opac' );
471 pass in 'opac' or 'intranet'. Defaults to 'opac'.
473 returns the full path to the appropriate directory containing images.
475 =cut
477 sub getitemtypeimagedir {
478 my $src = shift || 'opac';
479 if ($src eq 'intranet') {
480 return C4::Context->config('intrahtdocs') . '/' .C4::Context->preference('template') . '/img/itemtypeimg';
481 } else {
482 return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
486 sub getitemtypeimagesrc {
487 my $src = shift || 'opac';
488 if ($src eq 'intranet') {
489 return '/intranet-tmpl' . '/' . C4::Context->preference('template') . '/img/itemtypeimg';
490 } else {
491 return '/opac-tmpl' . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
495 sub getitemtypeimagelocation {
496 my ( $src, $image ) = @_;
498 return '' if ( !$image );
499 require URI::Split;
501 my $scheme = ( URI::Split::uri_split( $image ) )[0];
503 return $image if ( $scheme );
505 return getitemtypeimagesrc( $src ) . '/' . $image;
508 =head3 _getImagesFromDirectory
510 Find all of the image files in a directory in the filesystem
512 parameters: a directory name
514 returns: a list of images in that directory.
516 Notes: this does not traverse into subdirectories. See
517 _getSubdirectoryNames for help with that.
518 Images are assumed to be files with .gif or .png file extensions.
519 The image names returned do not have the directory name on them.
521 =cut
523 sub _getImagesFromDirectory {
524 my $directoryname = shift;
525 return unless defined $directoryname;
526 return unless -d $directoryname;
528 if ( opendir ( my $dh, $directoryname ) ) {
529 my @images = grep { /\.(gif|png)$/i } readdir( $dh );
530 closedir $dh;
531 @images = sort(@images);
532 return @images;
533 } else {
534 warn "unable to opendir $directoryname: $!";
535 return;
539 =head3 _getSubdirectoryNames
541 Find all of the directories in a directory in the filesystem
543 parameters: a directory name
545 returns: a list of subdirectories in that directory.
547 Notes: this does not traverse into subdirectories. Only the first
548 level of subdirectories are returned.
549 The directory names returned don't have the parent directory name on them.
551 =cut
553 sub _getSubdirectoryNames {
554 my $directoryname = shift;
555 return unless defined $directoryname;
556 return unless -d $directoryname;
558 if ( opendir ( my $dh, $directoryname ) ) {
559 my @directories = grep { -d File::Spec->catfile( $directoryname, $_ ) && ! ( /^\./ ) } readdir( $dh );
560 closedir $dh;
561 return @directories;
562 } else {
563 warn "unable to opendir $directoryname: $!";
564 return;
568 =head3 getImageSets
570 returns: a listref of hashrefs. Each hash represents another collection of images.
572 { imagesetname => 'npl', # the name of the image set (npl is the original one)
573 images => listref of image hashrefs
576 each image is represented by a hashref like this:
578 { KohaImage => 'npl/image.gif',
579 StaffImageUrl => '/intranet-tmpl/prog/img/itemtypeimg/npl/image.gif',
580 OpacImageURL => '/opac-tmpl/prog/itemtypeimg/npl/image.gif'
581 checked => 0 or 1: was this the image passed to this method?
582 Note: I'd like to remove this somehow.
585 =cut
587 sub getImageSets {
588 my %params = @_;
589 my $checked = $params{'checked'} || '';
591 my $paths = { staff => { filesystem => getitemtypeimagedir('intranet'),
592 url => getitemtypeimagesrc('intranet'),
594 opac => { filesystem => getitemtypeimagedir('opac'),
595 url => getitemtypeimagesrc('opac'),
599 my @imagesets = (); # list of hasrefs of image set data to pass to template
600 my @subdirectories = _getSubdirectoryNames( $paths->{'staff'}{'filesystem'} );
601 foreach my $imagesubdir ( @subdirectories ) {
602 warn $imagesubdir if $DEBUG;
603 my @imagelist = (); # hashrefs of image info
604 my @imagenames = _getImagesFromDirectory( File::Spec->catfile( $paths->{'staff'}{'filesystem'}, $imagesubdir ) );
605 my $imagesetactive = 0;
606 foreach my $thisimage ( @imagenames ) {
607 push( @imagelist,
608 { KohaImage => "$imagesubdir/$thisimage",
609 StaffImageUrl => join( '/', $paths->{'staff'}{'url'}, $imagesubdir, $thisimage ),
610 OpacImageUrl => join( '/', $paths->{'opac'}{'url'}, $imagesubdir, $thisimage ),
611 checked => "$imagesubdir/$thisimage" eq $checked ? 1 : 0,
614 $imagesetactive = 1 if "$imagesubdir/$thisimage" eq $checked;
616 push @imagesets, { imagesetname => $imagesubdir,
617 imagesetactive => $imagesetactive,
618 images => \@imagelist };
621 return \@imagesets;
624 =head2 GetPrinters
626 $printers = &GetPrinters();
627 @queues = keys %$printers;
629 Returns information about existing printer queues.
631 C<$printers> is a reference-to-hash whose keys are the print queues
632 defined in the printers table of the Koha database. The values are
633 references-to-hash, whose keys are the fields in the printers table.
635 =cut
637 sub GetPrinters {
638 my %printers;
639 my $dbh = C4::Context->dbh;
640 my $sth = $dbh->prepare("select * from printers");
641 $sth->execute;
642 while ( my $printer = $sth->fetchrow_hashref ) {
643 $printers{ $printer->{'printqueue'} } = $printer;
645 return ( \%printers );
648 =head2 GetPrinter
650 $printer = GetPrinter( $query, $printers );
652 =cut
654 sub GetPrinter {
655 my ( $query, $printers ) = @_; # get printer for this query from printers
656 my $printer = $query->param('printer');
657 my %cookie = $query->cookie('userenv');
658 ($printer) || ( $printer = $cookie{'printer'} ) || ( $printer = '' );
659 ( $printers->{$printer} ) || ( $printer = ( keys %$printers )[0] );
660 return $printer;
663 =head2 getnbpages
665 Returns the number of pages to display in a pagination bar, given the number
666 of items and the number of items per page.
668 =cut
670 sub getnbpages {
671 my ( $nb_items, $nb_items_per_page ) = @_;
673 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
676 =head2 getallthemes
678 (@themes) = &getallthemes('opac');
679 (@themes) = &getallthemes('intranet');
681 Returns an array of all available themes.
683 =cut
685 sub getallthemes {
686 my $type = shift;
687 my $htdocs;
688 my @themes;
689 if ( $type eq 'intranet' ) {
690 $htdocs = C4::Context->config('intrahtdocs');
692 else {
693 $htdocs = C4::Context->config('opachtdocs');
695 opendir D, "$htdocs";
696 my @dirlist = readdir D;
697 foreach my $directory (@dirlist) {
698 next if $directory eq 'lib';
699 -d "$htdocs/$directory/en" and push @themes, $directory;
701 return @themes;
704 sub getFacets {
705 my $facets;
706 if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
707 $facets = [
709 idx => 'su-to',
710 label => 'Topics',
711 tags => [ qw/ 600ab 601ab 602a 604at 605a 606ax 610a / ],
712 sep => ' - ',
715 idx => 'su-geo',
716 label => 'Places',
717 tags => [ qw/ 607a / ],
718 sep => ' - ',
721 idx => 'su-ut',
722 label => 'Titles',
723 tags => [ qw/ 500a 501a 503a / ],
724 sep => ', ',
727 idx => 'au',
728 label => 'Authors',
729 tags => [ qw/ 700ab 701ab 702ab / ],
730 sep => C4::Context->preference("UNIMARCAuthorsFacetsSeparator"),
733 idx => 'se',
734 label => 'Series',
735 tags => [ qw/ 225a / ],
736 sep => ', ',
739 idx => 'location',
740 label => 'Location',
741 tags => [ qw/ 995e / ],
745 unless ( Koha::Libraries->search->count == 1 )
747 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
748 if ( $DisplayLibraryFacets eq 'both'
749 || $DisplayLibraryFacets eq 'holding' )
751 push(
752 @$facets,
754 idx => 'holdingbranch',
755 label => 'HoldingLibrary',
756 tags => [qw / 995c /],
761 if ( $DisplayLibraryFacets eq 'both'
762 || $DisplayLibraryFacets eq 'home' )
764 push(
765 @$facets,
767 idx => 'homebranch',
768 label => 'HomeLibrary',
769 tags => [qw / 995b /],
775 else {
776 $facets = [
778 idx => 'su-to',
779 label => 'Topics',
780 tags => [ qw/ 650a / ],
781 sep => '--',
784 # idx => 'su-na',
785 # label => 'People and Organizations',
786 # tags => [ qw/ 600a 610a 611a / ],
787 # sep => 'a',
788 # },
790 idx => 'su-geo',
791 label => 'Places',
792 tags => [ qw/ 651a / ],
793 sep => '--',
796 idx => 'su-ut',
797 label => 'Titles',
798 tags => [ qw/ 630a / ],
799 sep => '--',
802 idx => 'au',
803 label => 'Authors',
804 tags => [ qw/ 100a 110a 700a / ],
805 sep => ', ',
808 idx => 'se',
809 label => 'Series',
810 tags => [ qw/ 440a 490a / ],
811 sep => ', ',
814 idx => 'itype',
815 label => 'ItemTypes',
816 tags => [ qw/ 952y 942c / ],
817 sep => ', ',
820 idx => 'location',
821 label => 'Location',
822 tags => [ qw / 952c / ],
826 unless ( Koha::Libraries->search->count == 1 )
828 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
829 if ( $DisplayLibraryFacets eq 'both'
830 || $DisplayLibraryFacets eq 'holding' )
832 push(
833 @$facets,
835 idx => 'holdingbranch',
836 label => 'HoldingLibrary',
837 tags => [qw / 952b /],
842 if ( $DisplayLibraryFacets eq 'both'
843 || $DisplayLibraryFacets eq 'home' )
845 push(
846 @$facets,
848 idx => 'homebranch',
849 label => 'HomeLibrary',
850 tags => [qw / 952a /],
856 return $facets;
859 =head2 get_infos_of
861 Return a href where a key is associated to a href. You give a query,
862 the name of the key among the fields returned by the query. If you
863 also give as third argument the name of the value, the function
864 returns a href of scalar. The optional 4th argument is an arrayref of
865 items passed to the C<execute()> call. It is designed to bind
866 parameters to any placeholders in your SQL.
868 my $query = '
869 SELECT itemnumber,
870 notforloan,
871 barcode
872 FROM items
875 # generic href of any information on the item, href of href.
876 my $iteminfos_of = get_infos_of($query, 'itemnumber');
877 print $iteminfos_of->{$itemnumber}{barcode};
879 # specific information, href of scalar
880 my $barcode_of_item = get_infos_of($query, 'itemnumber', 'barcode');
881 print $barcode_of_item->{$itemnumber};
883 =cut
885 sub get_infos_of {
886 my ( $query, $key_name, $value_name, $bind_params ) = @_;
888 my $dbh = C4::Context->dbh;
890 my $sth = $dbh->prepare($query);
891 $sth->execute( @$bind_params );
893 my %infos_of;
894 while ( my $row = $sth->fetchrow_hashref ) {
895 if ( defined $value_name ) {
896 $infos_of{ $row->{$key_name} } = $row->{$value_name};
898 else {
899 $infos_of{ $row->{$key_name} } = $row;
902 $sth->finish;
904 return \%infos_of;
907 =head2 get_notforloan_label_of
909 my $notforloan_label_of = get_notforloan_label_of();
911 Each authorised value of notforloan (information available in items and
912 itemtypes) is link to a single label.
914 Returns a href where keys are authorised values and values are corresponding
915 labels.
917 foreach my $authorised_value (keys %{$notforloan_label_of}) {
918 printf(
919 "authorised_value: %s => %s\n",
920 $authorised_value,
921 $notforloan_label_of->{$authorised_value}
925 =cut
927 # FIXME - why not use GetAuthorisedValues ??
929 sub get_notforloan_label_of {
930 my $dbh = C4::Context->dbh;
932 my $query = '
933 SELECT authorised_value
934 FROM marc_subfield_structure
935 WHERE kohafield = \'items.notforloan\'
936 LIMIT 0, 1
938 my $sth = $dbh->prepare($query);
939 $sth->execute();
940 my ($statuscode) = $sth->fetchrow_array();
942 $query = '
943 SELECT lib,
944 authorised_value
945 FROM authorised_values
946 WHERE category = ?
948 $sth = $dbh->prepare($query);
949 $sth->execute($statuscode);
950 my %notforloan_label_of;
951 while ( my $row = $sth->fetchrow_hashref ) {
952 $notforloan_label_of{ $row->{authorised_value} } = $row->{lib};
954 $sth->finish;
956 return \%notforloan_label_of;
959 =head2 GetAuthValCode
961 $authvalcode = GetAuthValCode($kohafield,$frameworkcode);
963 =cut
965 sub GetAuthValCode {
966 my ($kohafield,$fwcode) = @_;
967 my $dbh = C4::Context->dbh;
968 $fwcode='' unless $fwcode;
969 my $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield=? and frameworkcode=?');
970 $sth->execute($kohafield,$fwcode);
971 my ($authvalcode) = $sth->fetchrow_array;
972 return $authvalcode;
975 =head2 GetAuthValCodeFromField
977 $authvalcode = GetAuthValCodeFromField($field,$subfield,$frameworkcode);
979 C<$subfield> can be undefined
981 =cut
983 sub GetAuthValCodeFromField {
984 my ($field,$subfield,$fwcode) = @_;
985 my $dbh = C4::Context->dbh;
986 $fwcode='' unless $fwcode;
987 my $sth;
988 if (defined $subfield) {
989 $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?');
990 $sth->execute($field,$subfield,$fwcode);
991 } else {
992 $sth = $dbh->prepare('select authorised_value from marc_tag_structure where tagfield=? and frameworkcode=?');
993 $sth->execute($field,$fwcode);
995 my ($authvalcode) = $sth->fetchrow_array;
996 return $authvalcode;
999 =head2 GetAuthorisedValues
1001 $authvalues = GetAuthorisedValues([$category], [$selected]);
1003 This function returns all authorised values from the'authorised_value' table in a reference to array of hashrefs.
1005 C<$category> returns authorised values for just one category (optional).
1007 C<$selected> adds a "selected => 1" entry to the hash if the
1008 authorised_value matches it. B<NOTE:> this feature should be considered
1009 deprecated as it may be removed in the future.
1011 C<$opac> If set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1013 =cut
1015 sub GetAuthorisedValues {
1016 my ( $category, $selected, $opac ) = @_;
1018 # TODO: the "selected" feature should be replaced by a utility function
1019 # somewhere else, it doesn't belong in here. For starters it makes
1020 # caching much more complicated. Or just let the UI logic handle it, it's
1021 # what it's for.
1023 # Is this cached already?
1024 $opac = $opac ? 1 : 0; # normalise to be safe
1025 my $branch_limit =
1026 C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
1027 my $selected_key = defined($selected) ? $selected : '';
1028 my $cache_key =
1029 "AuthorisedValues-$category-$selected_key-$opac-$branch_limit";
1030 my $cache = Koha::Cache->get_instance();
1031 my $result = $cache->get_from_cache($cache_key);
1032 return $result if $result;
1034 my @results;
1035 my $dbh = C4::Context->dbh;
1036 my $query = qq{
1037 SELECT *
1038 FROM authorised_values
1040 $query .= qq{
1041 LEFT JOIN authorised_values_branches ON ( id = av_id )
1042 } if $branch_limit;
1043 my @where_strings;
1044 my @where_args;
1045 if($category) {
1046 push @where_strings, "category = ?";
1047 push @where_args, $category;
1049 if($branch_limit) {
1050 push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
1051 push @where_args, $branch_limit;
1053 if(@where_strings > 0) {
1054 $query .= " WHERE " . join(" AND ", @where_strings);
1056 $query .= " GROUP BY lib";
1057 $query .= ' ORDER BY category, ' . (
1058 $opac ? 'COALESCE(lib_opac, lib)'
1059 : 'lib, lib_opac'
1062 my $sth = $dbh->prepare($query);
1064 $sth->execute( @where_args );
1065 while (my $data=$sth->fetchrow_hashref) {
1066 if ( defined $selected and $selected eq $data->{authorised_value} ) {
1067 $data->{selected} = 1;
1069 else {
1070 $data->{selected} = 0;
1073 if ($opac && $data->{lib_opac}) {
1074 $data->{lib} = $data->{lib_opac};
1076 push @results, $data;
1078 $sth->finish;
1080 # We can't cache for long because of that "selected" thing which
1081 # makes it impossible to clear the cache without iterating through every
1082 # value, which sucks. This'll cover this request, and not a whole lot more.
1083 $cache->set_in_cache( $cache_key, \@results, { deepcopy => 1, expiry => 5 } );
1084 return \@results;
1087 =head2 GetAuthorisedValueCategories
1089 $auth_categories = GetAuthorisedValueCategories();
1091 Return an arrayref of all of the available authorised
1092 value categories.
1094 =cut
1096 sub GetAuthorisedValueCategories {
1097 my $dbh = C4::Context->dbh;
1098 my $sth = $dbh->prepare("SELECT DISTINCT category FROM authorised_values ORDER BY category");
1099 $sth->execute;
1100 my @results;
1101 while (defined (my $category = $sth->fetchrow_array) ) {
1102 push @results, $category;
1104 return \@results;
1107 =head2 GetAuthorisedValueByCode
1109 $authorised_value = GetAuthorisedValueByCode( $category, $authvalcode, $opac );
1111 Return the lib attribute from authorised_values from the row identified
1112 by the passed category and code
1114 =cut
1116 sub GetAuthorisedValueByCode {
1117 my ( $category, $authvalcode, $opac ) = @_;
1119 my $field = $opac ? 'lib_opac' : 'lib';
1120 my $dbh = C4::Context->dbh;
1121 my $sth = $dbh->prepare("SELECT $field FROM authorised_values WHERE category=? AND authorised_value =?");
1122 $sth->execute( $category, $authvalcode );
1123 while ( my $data = $sth->fetchrow_hashref ) {
1124 return $data->{ $field };
1128 =head2 GetKohaAuthorisedValues
1130 Takes $kohafield, $fwcode as parameters.
1132 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1134 Returns hashref of Code => description
1136 Returns undef if no authorised value category is defined for the kohafield.
1138 =cut
1140 sub GetKohaAuthorisedValues {
1141 my ($kohafield,$fwcode,$opac) = @_;
1142 $fwcode='' unless $fwcode;
1143 my %values;
1144 my $dbh = C4::Context->dbh;
1145 my $avcode = GetAuthValCode($kohafield,$fwcode);
1146 if ($avcode) {
1147 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1148 $sth->execute($avcode);
1149 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1150 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1152 return \%values;
1153 } else {
1154 return;
1158 =head2 GetKohaAuthorisedValuesFromField
1160 Takes $field, $subfield, $fwcode as parameters.
1162 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1163 $subfield can be undefined
1165 Returns hashref of Code => description
1167 Returns undef if no authorised value category is defined for the given field and subfield
1169 =cut
1171 sub GetKohaAuthorisedValuesFromField {
1172 my ($field, $subfield, $fwcode,$opac) = @_;
1173 $fwcode='' unless $fwcode;
1174 my %values;
1175 my $dbh = C4::Context->dbh;
1176 my $avcode = GetAuthValCodeFromField($field, $subfield, $fwcode);
1177 if ($avcode) {
1178 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1179 $sth->execute($avcode);
1180 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1181 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1183 return \%values;
1184 } else {
1185 return;
1189 =head2 GetKohaAuthorisedValuesMapping
1191 Takes a hash as a parameter. The interface key indicates the
1192 description to use in the mapping.
1194 Returns hashref of:
1195 "{kohafield},{frameworkcode},{authorised_value}" => "{description}"
1196 for all the kohafields, frameworkcodes, and authorised values.
1198 Returns undef if nothing is found.
1200 =cut
1202 sub GetKohaAuthorisedValuesMapping {
1203 my ($parameter) = @_;
1204 my $interface = $parameter->{'interface'} // '';
1206 my $query_mapping = q{
1207 SELECT TA.kohafield,TA.authorised_value AS category,
1208 TA.frameworkcode,TB.authorised_value,
1209 IF(TB.lib_opac>'',TB.lib_opac,TB.lib) AS OPAC,
1210 TB.lib AS Intranet,TB.lib_opac
1211 FROM marc_subfield_structure AS TA JOIN
1212 authorised_values as TB ON
1213 TA.authorised_value=TB.category
1214 WHERE TA.kohafield>'' AND TA.authorised_value>'';
1216 my $dbh = C4::Context->dbh;
1217 my $sth = $dbh->prepare($query_mapping);
1218 $sth->execute();
1219 my $avmapping;
1220 if ($interface eq 'opac') {
1221 while (my $row = $sth->fetchrow_hashref) {
1222 $avmapping->{$row->{kohafield}.",".$row->{frameworkcode}.",".$row->{authorised_value}} = $row->{OPAC};
1225 else {
1226 while (my $row = $sth->fetchrow_hashref) {
1227 $avmapping->{$row->{kohafield}.",".$row->{frameworkcode}.",".$row->{authorised_value}} = $row->{Intranet};
1230 return $avmapping;
1233 =head2 xml_escape
1235 my $escaped_string = C4::Koha::xml_escape($string);
1237 Convert &, <, >, ', and " in a string to XML entities
1239 =cut
1241 sub xml_escape {
1242 my $str = shift;
1243 return '' unless defined $str;
1244 $str =~ s/&/&amp;/g;
1245 $str =~ s/</&lt;/g;
1246 $str =~ s/>/&gt;/g;
1247 $str =~ s/'/&apos;/g;
1248 $str =~ s/"/&quot;/g;
1249 return $str;
1252 =head2 GetKohaAuthorisedValueLib
1254 Takes $category, $authorised_value as parameters.
1256 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1258 Returns authorised value description
1260 =cut
1262 sub GetKohaAuthorisedValueLib {
1263 my ($category,$authorised_value,$opac) = @_;
1264 my $value;
1265 my $dbh = C4::Context->dbh;
1266 my $sth = $dbh->prepare("select lib, lib_opac from authorised_values where category=? and authorised_value=?");
1267 $sth->execute($category,$authorised_value);
1268 my $data = $sth->fetchrow_hashref;
1269 $value = ($opac && $$data{'lib_opac'}) ? $$data{'lib_opac'} : $$data{'lib'};
1270 return $value;
1273 =head2 display_marc_indicators
1275 my $display_form = C4::Koha::display_marc_indicators($field);
1277 C<$field> is a MARC::Field object
1279 Generate a display form of the indicators of a variable
1280 MARC field, replacing any blanks with '#'.
1282 =cut
1284 sub display_marc_indicators {
1285 my $field = shift;
1286 my $indicators = '';
1287 if ($field && $field->tag() >= 10) {
1288 $indicators = $field->indicator(1) . $field->indicator(2);
1289 $indicators =~ s/ /#/g;
1291 return $indicators;
1294 sub GetNormalizedUPC {
1295 my ($marcrecord,$marcflavour) = @_;
1297 return unless $marcrecord;
1298 if ($marcflavour eq 'UNIMARC') {
1299 my @fields = $marcrecord->field('072');
1300 foreach my $field (@fields) {
1301 my $upc = _normalize_match_point($field->subfield('a'));
1302 if ($upc) {
1303 return $upc;
1308 else { # assume marc21 if not unimarc
1309 my @fields = $marcrecord->field('024');
1310 foreach my $field (@fields) {
1311 my $indicator = $field->indicator(1);
1312 my $upc = _normalize_match_point($field->subfield('a'));
1313 if ($upc && $indicator == 1 ) {
1314 return $upc;
1320 # Normalizes and returns the first valid ISBN found in the record
1321 # ISBN13 are converted into ISBN10. This is required to get some book cover images.
1322 sub GetNormalizedISBN {
1323 my ($isbn,$marcrecord,$marcflavour) = @_;
1324 if ($isbn) {
1325 # Koha attempts to store multiple ISBNs in biblioitems.isbn, separated by " | "
1326 # anything after " | " should be removed, along with the delimiter
1327 ($isbn) = split(/\|/, $isbn );
1328 return _isbn_cleanup($isbn);
1331 return unless $marcrecord;
1333 if ($marcflavour eq 'UNIMARC') {
1334 my @fields = $marcrecord->field('010');
1335 foreach my $field (@fields) {
1336 my $isbn = $field->subfield('a');
1337 if ($isbn) {
1338 return _isbn_cleanup($isbn);
1342 else { # assume marc21 if not unimarc
1343 my @fields = $marcrecord->field('020');
1344 foreach my $field (@fields) {
1345 $isbn = $field->subfield('a');
1346 if ($isbn) {
1347 return _isbn_cleanup($isbn);
1353 sub GetNormalizedEAN {
1354 my ($marcrecord,$marcflavour) = @_;
1356 return unless $marcrecord;
1358 if ($marcflavour eq 'UNIMARC') {
1359 my @fields = $marcrecord->field('073');
1360 foreach my $field (@fields) {
1361 my $ean = _normalize_match_point($field->subfield('a'));
1362 if ( $ean ) {
1363 return $ean;
1367 else { # assume marc21 if not unimarc
1368 my @fields = $marcrecord->field('024');
1369 foreach my $field (@fields) {
1370 my $indicator = $field->indicator(1);
1371 my $ean = _normalize_match_point($field->subfield('a'));
1372 if ( $ean && $indicator == 3 ) {
1373 return $ean;
1379 sub GetNormalizedOCLCNumber {
1380 my ($marcrecord,$marcflavour) = @_;
1381 return unless $marcrecord;
1383 if ($marcflavour ne 'UNIMARC' ) {
1384 my @fields = $marcrecord->field('035');
1385 foreach my $field (@fields) {
1386 my $oclc = $field->subfield('a');
1387 if ($oclc =~ /OCoLC/) {
1388 $oclc =~ s/\(OCoLC\)//;
1389 return $oclc;
1392 } else {
1393 # TODO for UNIMARC
1395 return
1398 sub GetAuthvalueDropbox {
1399 my ( $authcat, $default ) = @_;
1400 my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
1401 my $dbh = C4::Context->dbh;
1403 my $query = qq{
1404 SELECT *
1405 FROM authorised_values
1407 $query .= qq{
1408 LEFT JOIN authorised_values_branches ON ( id = av_id )
1409 } if $branch_limit;
1410 $query .= qq{
1411 WHERE category = ?
1413 $query .= " AND ( branchcode = ? OR branchcode IS NULL )" if $branch_limit;
1414 $query .= " GROUP BY lib ORDER BY category, lib, lib_opac";
1415 my $sth = $dbh->prepare($query);
1416 $sth->execute( $authcat, $branch_limit ? $branch_limit : () );
1419 my $option_list = [];
1420 my @authorised_values = ( q{} );
1421 while (my $av = $sth->fetchrow_hashref) {
1422 push @{$option_list}, {
1423 value => $av->{authorised_value},
1424 label => $av->{lib},
1425 default => ($default eq $av->{authorised_value}),
1429 if ( @{$option_list} ) {
1430 return $option_list;
1432 return;
1436 =head2 GetDailyQuote($opts)
1438 Takes a hashref of options
1440 Currently supported options are:
1442 'id' An exact quote id
1443 'random' Select a random quote
1444 noop When no option is passed in, this sub will return the quote timestamped for the current day
1446 The function returns an anonymous hash following this format:
1449 'source' => 'source-of-quote',
1450 'timestamp' => 'timestamp-value',
1451 'text' => 'text-of-quote',
1452 'id' => 'quote-id'
1455 =cut
1457 # This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
1458 # at least for default option
1460 sub GetDailyQuote {
1461 my %opts = @_;
1462 my $dbh = C4::Context->dbh;
1463 my $query = '';
1464 my $sth = undef;
1465 my $quote = undef;
1466 if ($opts{'id'}) {
1467 $query = 'SELECT * FROM quotes WHERE id = ?';
1468 $sth = $dbh->prepare($query);
1469 $sth->execute($opts{'id'});
1470 $quote = $sth->fetchrow_hashref();
1472 elsif ($opts{'random'}) {
1473 # Fall through... we also return a random quote as a catch-all if all else fails
1475 else {
1476 $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp DESC LIMIT 0,1';
1477 $sth = $dbh->prepare($query);
1478 $sth->execute();
1479 $quote = $sth->fetchrow_hashref();
1481 unless ($quote) { # if there are not matches, choose a random quote
1482 # get a list of all available quote ids
1483 $sth = C4::Context->dbh->prepare('SELECT count(*) FROM quotes;');
1484 $sth->execute;
1485 my $range = ($sth->fetchrow_array)[0];
1486 # chose a random id within that range if there is more than one quote
1487 my $offset = int(rand($range));
1488 # grab it
1489 $query = 'SELECT * FROM quotes ORDER BY id LIMIT 1 OFFSET ?';
1490 $sth = C4::Context->dbh->prepare($query);
1491 # see http://www.perlmonks.org/?node_id=837422 for why
1492 # we're being verbose and using bind_param
1493 $sth->bind_param(1, $offset, SQL_INTEGER);
1494 $sth->execute();
1495 $quote = $sth->fetchrow_hashref();
1496 # update the timestamp for that quote
1497 $query = 'UPDATE quotes SET timestamp = ? WHERE id = ?';
1498 $sth = C4::Context->dbh->prepare($query);
1499 $sth->execute(
1500 DateTime::Format::MySQL->format_datetime( dt_from_string() ),
1501 $quote->{'id'}
1504 return $quote;
1507 sub _normalize_match_point {
1508 my $match_point = shift;
1509 (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
1510 $normalized_match_point =~ s/-//g;
1512 return $normalized_match_point;
1515 sub _isbn_cleanup {
1516 my ($isbn) = @_;
1517 return NormalizeISBN(
1519 isbn => $isbn,
1520 format => 'ISBN-10',
1521 strip_hyphens => 1,
1523 ) if $isbn;
1526 =head2 NormalizedISBN
1528 my $isbns = NormalizedISBN({
1529 isbn => $isbn,
1530 strip_hyphens => [0,1],
1531 format => ['ISBN-10', 'ISBN-13']
1534 Returns an isbn validated by Business::ISBN.
1535 Optionally strips hyphens and/or forces the isbn
1536 to be of the specified format.
1538 If the string cannot be validated as an isbn,
1539 it returns nothing.
1541 =cut
1543 sub NormalizeISBN {
1544 my ($params) = @_;
1546 my $string = $params->{isbn};
1547 my $strip_hyphens = $params->{strip_hyphens};
1548 my $format = $params->{format};
1550 return unless $string;
1552 my $isbn = Business::ISBN->new($string);
1554 if ( $isbn && $isbn->is_valid() ) {
1556 if ( $format eq 'ISBN-10' ) {
1557 $isbn = $isbn->as_isbn10();
1559 elsif ( $format eq 'ISBN-13' ) {
1560 $isbn = $isbn->as_isbn13();
1562 return unless $isbn;
1564 if ($strip_hyphens) {
1565 $string = $isbn->as_string( [] );
1566 } else {
1567 $string = $isbn->as_string();
1570 return $string;
1574 =head2 GetVariationsOfISBN
1576 my @isbns = GetVariationsOfISBN( $isbn );
1578 Returns a list of variations of the given isbn in
1579 both ISBN-10 and ISBN-13 formats, with and without
1580 hyphens.
1582 In a scalar context, the isbns are returned as a
1583 string delimited by ' | '.
1585 =cut
1587 sub GetVariationsOfISBN {
1588 my ($isbn) = @_;
1590 return unless $isbn;
1592 my @isbns;
1594 push( @isbns, NormalizeISBN({ isbn => $isbn }) );
1595 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10' }) );
1596 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13' }) );
1597 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10', strip_hyphens => 1 }) );
1598 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13', strip_hyphens => 1 }) );
1600 # Strip out any "empty" strings from the array
1601 @isbns = grep { defined($_) && $_ =~ /\S/ } @isbns;
1603 return wantarray ? @isbns : join( " | ", @isbns );
1606 =head2 GetVariationsOfISBNs
1608 my @isbns = GetVariationsOfISBNs( @isbns );
1610 Returns a list of variations of the given isbns in
1611 both ISBN-10 and ISBN-13 formats, with and without
1612 hyphens.
1614 In a scalar context, the isbns are returned as a
1615 string delimited by ' | '.
1617 =cut
1619 sub GetVariationsOfISBNs {
1620 my (@isbns) = @_;
1622 @isbns = map { GetVariationsOfISBN( $_ ) } @isbns;
1624 return wantarray ? @isbns : join( " | ", @isbns );
1627 =head2 IsKohaFieldLinked
1629 my $is_linked = IsKohaFieldLinked({
1630 kohafield => $kohafield,
1631 frameworkcode => $frameworkcode,
1634 Return 1 if the field is linked
1636 =cut
1638 sub IsKohaFieldLinked {
1639 my ( $params ) = @_;
1640 my $kohafield = $params->{kohafield};
1641 my $frameworkcode = $params->{frameworkcode} || '';
1642 my $dbh = C4::Context->dbh;
1643 my $is_linked = $dbh->selectcol_arrayref( q|
1644 SELECT COUNT(*)
1645 FROM marc_subfield_structure
1646 WHERE frameworkcode = ?
1647 AND kohafield = ?
1648 |,{}, $frameworkcode, $kohafield );
1649 return $is_linked->[0];
1654 __END__
1656 =head1 AUTHOR
1658 Koha Team
1660 =cut