Bug 14585: Fixing up online help on main page
[koha.git] / C4 / Koha.pm
blobb2708db80fb67cc76735a8bef7d156a19a0623df
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 qw(GetBranchesCount);
28 use Koha::Cache;
29 use Koha::DateUtils qw(dt_from_string);
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.18.08.000;
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 =head1 NAME
88 C4::Koha - Perl Module containing convenience functions for Koha scripts
90 =head1 SYNOPSIS
92 use C4::Koha;
94 =head1 DESCRIPTION
96 Koha.pm provides many functions for Koha scripts.
98 =head1 FUNCTIONS
100 =cut
102 =head2 slashifyDate
104 $slash_date = &slashifyDate($dash_date);
106 Takes a string of the form "DD-MM-YYYY" (or anything separated by
107 dashes), converts it to the form "YYYY/MM/DD", and returns the result.
109 =cut
111 sub slashifyDate {
113 # accepts a date of the form xx-xx-xx[xx] and returns it in the
114 # form xx/xx/xx[xx]
115 my @dateOut = split( '-', shift );
116 return ("$dateOut[2]/$dateOut[1]/$dateOut[0]");
119 # FIXME.. this should be moved to a MARC-specific module
120 sub subfield_is_koha_internal_p {
121 my ($subfield) = @_;
123 # We could match on 'lib' and 'tab' (and 'mandatory', & more to come!)
124 # But real MARC subfields are always single-character
125 # so it really is safer just to check the length
127 return length $subfield != 1;
130 =head2 GetSupportName
132 $itemtypename = &GetSupportName($codestring);
134 Returns a string with the name of the itemtype.
136 =cut
138 sub GetSupportName{
139 my ($codestring)=@_;
140 return if (! $codestring);
141 my $resultstring;
142 my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
143 if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') {
144 my $query = qq|
145 SELECT description
146 FROM itemtypes
147 WHERE itemtype=?
148 order by description
150 my $sth = C4::Context->dbh->prepare($query);
151 $sth->execute($codestring);
152 ($resultstring)=$sth->fetchrow;
153 return $resultstring;
154 } else {
155 my $sth =
156 C4::Context->dbh->prepare(
157 "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
159 $sth->execute( $advanced_search_types, $codestring );
160 my $data = $sth->fetchrow_hashref;
161 return $$data{'lib'};
165 =head2 GetSupportList
167 $itemtypes = &GetSupportList();
169 Returns an array ref containing informations about Support (since itemtype is rather a circulation code when item-level-itypes is used).
171 build a HTML select with the following code :
173 =head3 in PERL SCRIPT
175 my $itemtypes = GetSupportList();
176 $template->param(itemtypeloop => $itemtypes);
178 =head3 in TEMPLATE
180 <select name="itemtype" id="itemtype">
181 <option value=""></option>
182 [% FOREACH itemtypeloo IN itemtypeloop %]
183 [% IF ( itemtypeloo.selected ) %]
184 <option value="[% itemtypeloo.itemtype %]" selected="selected">[% itemtypeloo.description %]</option>
185 [% ELSE %]
186 <option value="[% itemtypeloo.itemtype %]">[% itemtypeloo.description %]</option>
187 [% END %]
188 [% END %]
189 </select>
191 =cut
193 sub GetSupportList{
194 my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
195 if (!$advanced_search_types or $advanced_search_types =~ /itemtypes/) {
196 my $query = qq|
197 SELECT *
198 FROM itemtypes
199 order by description
201 my $sth = C4::Context->dbh->prepare($query);
202 $sth->execute;
203 return $sth->fetchall_arrayref({});
204 } else {
205 my $advsearchtypes = GetAuthorisedValues($advanced_search_types);
206 my @results= map {{itemtype=>$$_{authorised_value},description=>$$_{lib},imageurl=>$$_{imageurl}}} @$advsearchtypes;
207 return \@results;
210 =head2 GetItemTypes
212 $itemtypes = &GetItemTypes( style => $style );
214 Returns information about existing itemtypes.
216 Params:
217 style: either 'array' or 'hash', defaults to 'hash'.
218 'array' returns an arrayref,
219 'hash' return a hashref with the itemtype value as the key
221 build a HTML select with the following code :
223 =head3 in PERL SCRIPT
225 my $itemtypes = GetItemTypes;
226 my @itemtypesloop;
227 foreach my $thisitemtype (sort keys %$itemtypes) {
228 my $selected = 1 if $thisitemtype eq $itemtype;
229 my %row =(value => $thisitemtype,
230 selected => $selected,
231 description => $itemtypes->{$thisitemtype}->{'description'},
233 push @itemtypesloop, \%row;
235 $template->param(itemtypeloop => \@itemtypesloop);
237 =head3 in TEMPLATE
239 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
240 <select name="itemtype">
241 <option value="">Default</option>
242 <!-- TMPL_LOOP name="itemtypeloop" -->
243 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="description" --></option>
244 <!-- /TMPL_LOOP -->
245 </select>
246 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
247 <input type="submit" value="OK" class="button">
248 </form>
250 =cut
252 sub GetItemTypes {
253 my ( %params ) = @_;
254 my $style = defined( $params{'style'} ) ? $params{'style'} : 'hash';
256 # returns a reference to a hash of references to itemtypes...
257 my %itemtypes;
258 my $dbh = C4::Context->dbh;
259 my $query = qq|
260 SELECT *
261 FROM itemtypes
263 my $sth = $dbh->prepare($query);
264 $sth->execute;
266 if ( $style eq 'hash' ) {
267 while ( my $IT = $sth->fetchrow_hashref ) {
268 $itemtypes{ $IT->{'itemtype'} } = $IT;
270 return ( \%itemtypes );
271 } else {
272 return $sth->fetchall_arrayref({});
276 sub get_itemtypeinfos_of {
277 my @itemtypes = @_;
279 my $placeholders = join( ', ', map { '?' } @itemtypes );
280 my $query = <<"END_SQL";
281 SELECT itemtype,
282 description,
283 imageurl,
284 notforloan
285 FROM itemtypes
286 WHERE itemtype IN ( $placeholders )
287 END_SQL
289 return get_infos_of( $query, 'itemtype', undef, \@itemtypes );
292 =head2 getauthtypes
294 $authtypes = &getauthtypes();
296 Returns information about existing authtypes.
298 build a HTML select with the following code :
300 =head3 in PERL SCRIPT
302 my $authtypes = getauthtypes;
303 my @authtypesloop;
304 foreach my $thisauthtype (keys %$authtypes) {
305 my $selected = 1 if $thisauthtype eq $authtype;
306 my %row =(value => $thisauthtype,
307 selected => $selected,
308 authtypetext => $authtypes->{$thisauthtype}->{'authtypetext'},
310 push @authtypesloop, \%row;
312 $template->param(itemtypeloop => \@itemtypesloop);
314 =head3 in TEMPLATE
316 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
317 <select name="authtype">
318 <!-- TMPL_LOOP name="authtypeloop" -->
319 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="authtypetext" --></option>
320 <!-- /TMPL_LOOP -->
321 </select>
322 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
323 <input type="submit" value="OK" class="button">
324 </form>
327 =cut
329 sub getauthtypes {
331 # returns a reference to a hash of references to authtypes...
332 my %authtypes;
333 my $dbh = C4::Context->dbh;
334 my $sth = $dbh->prepare("select * from auth_types order by authtypetext");
335 $sth->execute;
336 while ( my $IT = $sth->fetchrow_hashref ) {
337 $authtypes{ $IT->{'authtypecode'} } = $IT;
339 return ( \%authtypes );
342 sub getauthtype {
343 my ($authtypecode) = @_;
345 # returns a reference to a hash of references to authtypes...
346 my %authtypes;
347 my $dbh = C4::Context->dbh;
348 my $sth = $dbh->prepare("select * from auth_types where authtypecode=?");
349 $sth->execute($authtypecode);
350 my $res = $sth->fetchrow_hashref;
351 return $res;
354 =head2 getframework
356 $frameworks = &getframework();
358 Returns information about existing frameworks
360 build a HTML select with the following code :
362 =head3 in PERL SCRIPT
364 my $frameworks = getframeworks();
365 my @frameworkloop;
366 foreach my $thisframework (keys %$frameworks) {
367 my $selected = 1 if $thisframework eq $frameworkcode;
368 my %row =(
369 value => $thisframework,
370 selected => $selected,
371 description => $frameworks->{$thisframework}->{'frameworktext'},
373 push @frameworksloop, \%row;
375 $template->param(frameworkloop => \@frameworksloop);
377 =head3 in TEMPLATE
379 <form action="[% script_name %] method=post>
380 <select name="frameworkcode">
381 <option value="">Default</option>
382 [% FOREACH framework IN frameworkloop %]
383 [% IF ( framework.selected ) %]
384 <option value="[% framework.value %]" selected="selected">[% framework.description %]</option>
385 [% ELSE %]
386 <option value="[% framework.value %]">[% framework.description %]</option>
387 [% END %]
388 [% END %]
389 </select>
390 <input type=text name=searchfield value="[% searchfield %]">
391 <input type="submit" value="OK" class="button">
392 </form>
394 =cut
396 sub getframeworks {
398 # returns a reference to a hash of references to branches...
399 my %itemtypes;
400 my $dbh = C4::Context->dbh;
401 my $sth = $dbh->prepare("select * from biblio_framework");
402 $sth->execute;
403 while ( my $IT = $sth->fetchrow_hashref ) {
404 $itemtypes{ $IT->{'frameworkcode'} } = $IT;
406 return ( \%itemtypes );
409 =head2 GetFrameworksLoop
411 $frameworks = GetFrameworksLoop( $frameworkcode );
413 Returns the loop suggested on getframework(), but ordered by framework description.
415 build a HTML select with the following code :
417 =head3 in PERL SCRIPT
419 $template->param( frameworkloop => GetFrameworksLoop( $frameworkcode ) );
421 =head3 in TEMPLATE
423 Same as getframework()
425 <form action="[% script_name %] method=post>
426 <select name="frameworkcode">
427 <option value="">Default</option>
428 [% FOREACH framework IN frameworkloop %]
429 [% IF ( framework.selected ) %]
430 <option value="[% framework.value %]" selected="selected">[% framework.description %]</option>
431 [% ELSE %]
432 <option value="[% framework.value %]">[% framework.description %]</option>
433 [% END %]
434 [% END %]
435 </select>
436 <input type=text name=searchfield value="[% searchfield %]">
437 <input type="submit" value="OK" class="button">
438 </form>
440 =cut
442 sub GetFrameworksLoop {
443 my $frameworkcode = shift;
444 my $frameworks = getframeworks();
445 my @frameworkloop;
446 foreach my $thisframework (sort { uc($frameworks->{$a}->{'frameworktext'}) cmp uc($frameworks->{$b}->{'frameworktext'}) } keys %$frameworks) {
447 my $selected = ( $thisframework eq $frameworkcode ) ? 1 : undef;
448 my %row = (
449 value => $thisframework,
450 selected => $selected,
451 description => $frameworks->{$thisframework}->{'frameworktext'},
453 push @frameworkloop, \%row;
455 return \@frameworkloop;
458 =head2 getframeworkinfo
460 $frameworkinfo = &getframeworkinfo($frameworkcode);
462 Returns information about an frameworkcode.
464 =cut
466 sub getframeworkinfo {
467 my ($frameworkcode) = @_;
468 my $dbh = C4::Context->dbh;
469 my $sth =
470 $dbh->prepare("select * from biblio_framework where frameworkcode=?");
471 $sth->execute($frameworkcode);
472 my $res = $sth->fetchrow_hashref;
473 return $res;
476 =head2 getitemtypeinfo
478 $itemtype = &getitemtypeinfo($itemtype, [$interface]);
480 Returns information about an itemtype. The optional $interface argument
481 sets which interface ('opac' or 'intranet') to return the imageurl for.
482 Defaults to intranet.
484 =cut
486 sub getitemtypeinfo {
487 my ($itemtype, $interface) = @_;
488 my $dbh = C4::Context->dbh;
489 my $sth = $dbh->prepare("select * from itemtypes where itemtype=?");
490 $sth->execute($itemtype);
491 my $res = $sth->fetchrow_hashref;
493 $res->{imageurl} = getitemtypeimagelocation( ( ( defined $interface && $interface eq 'opac' ) ? 'opac' : 'intranet' ), $res->{imageurl} );
495 return $res;
498 =head2 getitemtypeimagedir
500 my $directory = getitemtypeimagedir( 'opac' );
502 pass in 'opac' or 'intranet'. Defaults to 'opac'.
504 returns the full path to the appropriate directory containing images.
506 =cut
508 sub getitemtypeimagedir {
509 my $src = shift || 'opac';
510 if ($src eq 'intranet') {
511 return C4::Context->config('intrahtdocs') . '/' .C4::Context->preference('template') . '/img/itemtypeimg';
512 } else {
513 return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
517 sub getitemtypeimagesrc {
518 my $src = shift || 'opac';
519 if ($src eq 'intranet') {
520 return '/intranet-tmpl' . '/' . C4::Context->preference('template') . '/img/itemtypeimg';
521 } else {
522 return '/opac-tmpl' . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
526 sub getitemtypeimagelocation {
527 my ( $src, $image ) = @_;
529 return '' if ( !$image );
530 require URI::Split;
532 my $scheme = ( URI::Split::uri_split( $image ) )[0];
534 return $image if ( $scheme );
536 return getitemtypeimagesrc( $src ) . '/' . $image;
539 =head3 _getImagesFromDirectory
541 Find all of the image files in a directory in the filesystem
543 parameters: a directory name
545 returns: a list of images in that directory.
547 Notes: this does not traverse into subdirectories. See
548 _getSubdirectoryNames for help with that.
549 Images are assumed to be files with .gif or .png file extensions.
550 The image names returned do not have the directory name on them.
552 =cut
554 sub _getImagesFromDirectory {
555 my $directoryname = shift;
556 return unless defined $directoryname;
557 return unless -d $directoryname;
559 if ( opendir ( my $dh, $directoryname ) ) {
560 my @images = grep { /\.(gif|png)$/i } readdir( $dh );
561 closedir $dh;
562 @images = sort(@images);
563 return @images;
564 } else {
565 warn "unable to opendir $directoryname: $!";
566 return;
570 =head3 _getSubdirectoryNames
572 Find all of the directories in a directory in the filesystem
574 parameters: a directory name
576 returns: a list of subdirectories in that directory.
578 Notes: this does not traverse into subdirectories. Only the first
579 level of subdirectories are returned.
580 The directory names returned don't have the parent directory name on them.
582 =cut
584 sub _getSubdirectoryNames {
585 my $directoryname = shift;
586 return unless defined $directoryname;
587 return unless -d $directoryname;
589 if ( opendir ( my $dh, $directoryname ) ) {
590 my @directories = grep { -d File::Spec->catfile( $directoryname, $_ ) && ! ( /^\./ ) } readdir( $dh );
591 closedir $dh;
592 return @directories;
593 } else {
594 warn "unable to opendir $directoryname: $!";
595 return;
599 =head3 getImageSets
601 returns: a listref of hashrefs. Each hash represents another collection of images.
603 { imagesetname => 'npl', # the name of the image set (npl is the original one)
604 images => listref of image hashrefs
607 each image is represented by a hashref like this:
609 { KohaImage => 'npl/image.gif',
610 StaffImageUrl => '/intranet-tmpl/prog/img/itemtypeimg/npl/image.gif',
611 OpacImageURL => '/opac-tmpl/prog/itemtypeimg/npl/image.gif'
612 checked => 0 or 1: was this the image passed to this method?
613 Note: I'd like to remove this somehow.
616 =cut
618 sub getImageSets {
619 my %params = @_;
620 my $checked = $params{'checked'} || '';
622 my $paths = { staff => { filesystem => getitemtypeimagedir('intranet'),
623 url => getitemtypeimagesrc('intranet'),
625 opac => { filesystem => getitemtypeimagedir('opac'),
626 url => getitemtypeimagesrc('opac'),
630 my @imagesets = (); # list of hasrefs of image set data to pass to template
631 my @subdirectories = _getSubdirectoryNames( $paths->{'staff'}{'filesystem'} );
632 foreach my $imagesubdir ( @subdirectories ) {
633 warn $imagesubdir if $DEBUG;
634 my @imagelist = (); # hashrefs of image info
635 my @imagenames = _getImagesFromDirectory( File::Spec->catfile( $paths->{'staff'}{'filesystem'}, $imagesubdir ) );
636 my $imagesetactive = 0;
637 foreach my $thisimage ( @imagenames ) {
638 push( @imagelist,
639 { KohaImage => "$imagesubdir/$thisimage",
640 StaffImageUrl => join( '/', $paths->{'staff'}{'url'}, $imagesubdir, $thisimage ),
641 OpacImageUrl => join( '/', $paths->{'opac'}{'url'}, $imagesubdir, $thisimage ),
642 checked => "$imagesubdir/$thisimage" eq $checked ? 1 : 0,
645 $imagesetactive = 1 if "$imagesubdir/$thisimage" eq $checked;
647 push @imagesets, { imagesetname => $imagesubdir,
648 imagesetactive => $imagesetactive,
649 images => \@imagelist };
652 return \@imagesets;
655 =head2 GetPrinters
657 $printers = &GetPrinters();
658 @queues = keys %$printers;
660 Returns information about existing printer queues.
662 C<$printers> is a reference-to-hash whose keys are the print queues
663 defined in the printers table of the Koha database. The values are
664 references-to-hash, whose keys are the fields in the printers table.
666 =cut
668 sub GetPrinters {
669 my %printers;
670 my $dbh = C4::Context->dbh;
671 my $sth = $dbh->prepare("select * from printers");
672 $sth->execute;
673 while ( my $printer = $sth->fetchrow_hashref ) {
674 $printers{ $printer->{'printqueue'} } = $printer;
676 return ( \%printers );
679 =head2 GetPrinter
681 $printer = GetPrinter( $query, $printers );
683 =cut
685 sub GetPrinter {
686 my ( $query, $printers ) = @_; # get printer for this query from printers
687 my $printer = $query->param('printer');
688 my %cookie = $query->cookie('userenv');
689 ($printer) || ( $printer = $cookie{'printer'} ) || ( $printer = '' );
690 ( $printers->{$printer} ) || ( $printer = ( keys %$printers )[0] );
691 return $printer;
694 =head2 getnbpages
696 Returns the number of pages to display in a pagination bar, given the number
697 of items and the number of items per page.
699 =cut
701 sub getnbpages {
702 my ( $nb_items, $nb_items_per_page ) = @_;
704 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
707 =head2 getallthemes
709 (@themes) = &getallthemes('opac');
710 (@themes) = &getallthemes('intranet');
712 Returns an array of all available themes.
714 =cut
716 sub getallthemes {
717 my $type = shift;
718 my $htdocs;
719 my @themes;
720 if ( $type eq 'intranet' ) {
721 $htdocs = C4::Context->config('intrahtdocs');
723 else {
724 $htdocs = C4::Context->config('opachtdocs');
726 opendir D, "$htdocs";
727 my @dirlist = readdir D;
728 foreach my $directory (@dirlist) {
729 next if $directory eq 'lib';
730 -d "$htdocs/$directory/en" and push @themes, $directory;
732 return @themes;
735 sub getFacets {
736 my $facets;
737 if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
738 $facets = [
740 idx => 'su-to',
741 label => 'Topics',
742 tags => [ qw/ 600ab 601ab 602a 604at 605a 606ax 610a / ],
743 sep => ' - ',
746 idx => 'su-geo',
747 label => 'Places',
748 tags => [ qw/ 607a / ],
749 sep => ' - ',
752 idx => 'su-ut',
753 label => 'Titles',
754 tags => [ qw/ 500a 501a 503a / ],
755 sep => ', ',
758 idx => 'au',
759 label => 'Authors',
760 tags => [ qw/ 700ab 701ab 702ab / ],
761 sep => C4::Context->preference("UNIMARCAuthorsFacetsSeparator"),
764 idx => 'se',
765 label => 'Series',
766 tags => [ qw/ 225a / ],
767 sep => ', ',
770 idx => 'location',
771 label => 'Location',
772 tags => [ qw/ 995e / ],
776 unless ( C4::Context->preference("singleBranchMode")
777 || GetBranchesCount() == 1 )
779 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
780 if ( $DisplayLibraryFacets eq 'both'
781 || $DisplayLibraryFacets eq 'holding' )
783 push(
784 @$facets,
786 idx => 'holdingbranch',
787 label => 'HoldingLibrary',
788 tags => [qw / 995c /],
793 if ( $DisplayLibraryFacets eq 'both'
794 || $DisplayLibraryFacets eq 'home' )
796 push(
797 @$facets,
799 idx => 'homebranch',
800 label => 'HomeLibrary',
801 tags => [qw / 995b /],
807 else {
808 $facets = [
810 idx => 'su-to',
811 label => 'Topics',
812 tags => [ qw/ 650a / ],
813 sep => '--',
816 # idx => 'su-na',
817 # label => 'People and Organizations',
818 # tags => [ qw/ 600a 610a 611a / ],
819 # sep => 'a',
820 # },
822 idx => 'su-geo',
823 label => 'Places',
824 tags => [ qw/ 651a / ],
825 sep => '--',
828 idx => 'su-ut',
829 label => 'Titles',
830 tags => [ qw/ 630a / ],
831 sep => '--',
834 idx => 'au',
835 label => 'Authors',
836 tags => [ qw/ 100a 110a 700a / ],
837 sep => ', ',
840 idx => 'se',
841 label => 'Series',
842 tags => [ qw/ 440a 490a / ],
843 sep => ', ',
846 idx => 'itype',
847 label => 'ItemTypes',
848 tags => [ qw/ 952y 942c / ],
849 sep => ', ',
852 idx => 'location',
853 label => 'Location',
854 tags => [ qw / 952c / ],
858 unless ( C4::Context->preference("singleBranchMode")
859 || GetBranchesCount() == 1 )
861 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
862 if ( $DisplayLibraryFacets eq 'both'
863 || $DisplayLibraryFacets eq 'holding' )
865 push(
866 @$facets,
868 idx => 'holdingbranch',
869 label => 'HoldingLibrary',
870 tags => [qw / 952b /],
875 if ( $DisplayLibraryFacets eq 'both'
876 || $DisplayLibraryFacets eq 'home' )
878 push(
879 @$facets,
881 idx => 'homebranch',
882 label => 'HomeLibrary',
883 tags => [qw / 952a /],
889 return $facets;
892 =head2 get_infos_of
894 Return a href where a key is associated to a href. You give a query,
895 the name of the key among the fields returned by the query. If you
896 also give as third argument the name of the value, the function
897 returns a href of scalar. The optional 4th argument is an arrayref of
898 items passed to the C<execute()> call. It is designed to bind
899 parameters to any placeholders in your SQL.
901 my $query = '
902 SELECT itemnumber,
903 notforloan,
904 barcode
905 FROM items
908 # generic href of any information on the item, href of href.
909 my $iteminfos_of = get_infos_of($query, 'itemnumber');
910 print $iteminfos_of->{$itemnumber}{barcode};
912 # specific information, href of scalar
913 my $barcode_of_item = get_infos_of($query, 'itemnumber', 'barcode');
914 print $barcode_of_item->{$itemnumber};
916 =cut
918 sub get_infos_of {
919 my ( $query, $key_name, $value_name, $bind_params ) = @_;
921 my $dbh = C4::Context->dbh;
923 my $sth = $dbh->prepare($query);
924 $sth->execute( @$bind_params );
926 my %infos_of;
927 while ( my $row = $sth->fetchrow_hashref ) {
928 if ( defined $value_name ) {
929 $infos_of{ $row->{$key_name} } = $row->{$value_name};
931 else {
932 $infos_of{ $row->{$key_name} } = $row;
935 $sth->finish;
937 return \%infos_of;
940 =head2 get_notforloan_label_of
942 my $notforloan_label_of = get_notforloan_label_of();
944 Each authorised value of notforloan (information available in items and
945 itemtypes) is link to a single label.
947 Returns a href where keys are authorised values and values are corresponding
948 labels.
950 foreach my $authorised_value (keys %{$notforloan_label_of}) {
951 printf(
952 "authorised_value: %s => %s\n",
953 $authorised_value,
954 $notforloan_label_of->{$authorised_value}
958 =cut
960 # FIXME - why not use GetAuthorisedValues ??
962 sub get_notforloan_label_of {
963 my $dbh = C4::Context->dbh;
965 my $query = '
966 SELECT authorised_value
967 FROM marc_subfield_structure
968 WHERE kohafield = \'items.notforloan\'
969 LIMIT 0, 1
971 my $sth = $dbh->prepare($query);
972 $sth->execute();
973 my ($statuscode) = $sth->fetchrow_array();
975 $query = '
976 SELECT lib,
977 authorised_value
978 FROM authorised_values
979 WHERE category = ?
981 $sth = $dbh->prepare($query);
982 $sth->execute($statuscode);
983 my %notforloan_label_of;
984 while ( my $row = $sth->fetchrow_hashref ) {
985 $notforloan_label_of{ $row->{authorised_value} } = $row->{lib};
987 $sth->finish;
989 return \%notforloan_label_of;
992 =head2 displayServers
994 my $servers = displayServers();
995 my $servers = displayServers( $position );
996 my $servers = displayServers( $position, $type );
998 displayServers returns a listref of hashrefs, each containing
999 information about available z3950 servers. Each hashref has a format
1000 like:
1003 'checked' => 'checked',
1004 'encoding' => 'utf8',
1005 'icon' => undef,
1006 'id' => 'LIBRARY OF CONGRESS',
1007 'label' => '',
1008 'name' => 'server',
1009 'opensearch' => '',
1010 'value' => 'lx2.loc.gov:210/',
1011 'zed' => 1,
1014 =cut
1016 sub displayServers {
1017 my ( $position, $type ) = @_;
1018 my $dbh = C4::Context->dbh;
1020 my $strsth = 'SELECT * FROM z3950servers';
1021 my @where_clauses;
1022 my @bind_params;
1024 if ($position) {
1025 push @bind_params, $position;
1026 push @where_clauses, ' position = ? ';
1029 if ($type) {
1030 push @bind_params, $type;
1031 push @where_clauses, ' type = ? ';
1034 # reassemble where clause from where clause pieces
1035 if (@where_clauses) {
1036 $strsth .= ' WHERE ' . join( ' AND ', @where_clauses );
1039 my $rq = $dbh->prepare($strsth);
1040 $rq->execute(@bind_params);
1041 my @primaryserverloop;
1043 while ( my $data = $rq->fetchrow_hashref ) {
1044 push @primaryserverloop,
1045 { label => $data->{description},
1046 id => $data->{name},
1047 name => "server",
1048 value => $data->{host} . ":" . $data->{port} . "/" . $data->{database},
1049 encoding => ( $data->{encoding} ? $data->{encoding} : "iso-5426" ),
1050 checked => "checked",
1051 icon => $data->{icon},
1052 zed => $data->{type} eq 'zed',
1053 opensearch => $data->{type} eq 'opensearch'
1056 return \@primaryserverloop;
1060 =head2 GetKohaImageurlFromAuthorisedValues
1062 $authhorised_value = GetKohaImageurlFromAuthorisedValues( $category, $authvalcode );
1064 Return the first url of the authorised value image represented by $lib.
1066 =cut
1068 sub GetKohaImageurlFromAuthorisedValues {
1069 my ( $category, $lib ) = @_;
1070 my $dbh = C4::Context->dbh;
1071 my $sth = $dbh->prepare("SELECT imageurl FROM authorised_values WHERE category=? AND lib =?");
1072 $sth->execute( $category, $lib );
1073 while ( my $data = $sth->fetchrow_hashref ) {
1074 return $data->{'imageurl'};
1078 =head2 GetAuthValCode
1080 $authvalcode = GetAuthValCode($kohafield,$frameworkcode);
1082 =cut
1084 sub GetAuthValCode {
1085 my ($kohafield,$fwcode) = @_;
1086 my $dbh = C4::Context->dbh;
1087 $fwcode='' unless $fwcode;
1088 my $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield=? and frameworkcode=?');
1089 $sth->execute($kohafield,$fwcode);
1090 my ($authvalcode) = $sth->fetchrow_array;
1091 return $authvalcode;
1094 =head2 GetAuthValCodeFromField
1096 $authvalcode = GetAuthValCodeFromField($field,$subfield,$frameworkcode);
1098 C<$subfield> can be undefined
1100 =cut
1102 sub GetAuthValCodeFromField {
1103 my ($field,$subfield,$fwcode) = @_;
1104 my $dbh = C4::Context->dbh;
1105 $fwcode='' unless $fwcode;
1106 my $sth;
1107 if (defined $subfield) {
1108 $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?');
1109 $sth->execute($field,$subfield,$fwcode);
1110 } else {
1111 $sth = $dbh->prepare('select authorised_value from marc_tag_structure where tagfield=? and frameworkcode=?');
1112 $sth->execute($field,$fwcode);
1114 my ($authvalcode) = $sth->fetchrow_array;
1115 return $authvalcode;
1118 =head2 GetAuthorisedValues
1120 $authvalues = GetAuthorisedValues([$category], [$selected]);
1122 This function returns all authorised values from the'authorised_value' table in a reference to array of hashrefs.
1124 C<$category> returns authorised values for just one category (optional).
1126 C<$selected> adds a "selected => 1" entry to the hash if the
1127 authorised_value matches it. B<NOTE:> this feature should be considered
1128 deprecated as it may be removed in the future.
1130 C<$opac> If set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1132 =cut
1134 sub GetAuthorisedValues {
1135 my ( $category, $selected, $opac ) = @_;
1137 # TODO: the "selected" feature should be replaced by a utility function
1138 # somewhere else, it doesn't belong in here. For starters it makes
1139 # caching much more complicated. Or just let the UI logic handle it, it's
1140 # what it's for.
1142 # Is this cached already?
1143 $opac = $opac ? 1 : 0; # normalise to be safe
1144 my $branch_limit =
1145 C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
1146 my $selected_key = defined($selected) ? $selected : '';
1147 my $cache_key =
1148 "AuthorisedValues-$category-$selected_key-$opac-$branch_limit";
1149 my $cache = Koha::Cache->get_instance();
1150 my $result = $cache->get_from_cache($cache_key);
1151 return $result if $result;
1153 my @results;
1154 my $dbh = C4::Context->dbh;
1155 my $query = qq{
1156 SELECT *
1157 FROM authorised_values
1159 $query .= qq{
1160 LEFT JOIN authorised_values_branches ON ( id = av_id )
1161 } if $branch_limit;
1162 my @where_strings;
1163 my @where_args;
1164 if($category) {
1165 push @where_strings, "category = ?";
1166 push @where_args, $category;
1168 if($branch_limit) {
1169 push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
1170 push @where_args, $branch_limit;
1172 if(@where_strings > 0) {
1173 $query .= " WHERE " . join(" AND ", @where_strings);
1175 $query .= " GROUP BY lib";
1176 $query .= ' ORDER BY category, ' . (
1177 $opac ? 'COALESCE(lib_opac, lib)'
1178 : 'lib, lib_opac'
1181 my $sth = $dbh->prepare($query);
1183 $sth->execute( @where_args );
1184 while (my $data=$sth->fetchrow_hashref) {
1185 if ( defined $selected and $selected eq $data->{authorised_value} ) {
1186 $data->{selected} = 1;
1188 else {
1189 $data->{selected} = 0;
1192 if ($opac && $data->{lib_opac}) {
1193 $data->{lib} = $data->{lib_opac};
1195 push @results, $data;
1197 $sth->finish;
1199 # We can't cache for long because of that "selected" thing which
1200 # makes it impossible to clear the cache without iterating through every
1201 # value, which sucks. This'll cover this request, and not a whole lot more.
1202 $cache->set_in_cache( $cache_key, \@results, { deepcopy => 1, expiry => 5 } );
1203 return \@results;
1206 =head2 GetAuthorisedValueCategories
1208 $auth_categories = GetAuthorisedValueCategories();
1210 Return an arrayref of all of the available authorised
1211 value categories.
1213 =cut
1215 sub GetAuthorisedValueCategories {
1216 my $dbh = C4::Context->dbh;
1217 my $sth = $dbh->prepare("SELECT DISTINCT category FROM authorised_values ORDER BY category");
1218 $sth->execute;
1219 my @results;
1220 while (defined (my $category = $sth->fetchrow_array) ) {
1221 push @results, $category;
1223 return \@results;
1226 =head2 IsAuthorisedValueCategory
1228 $is_auth_val_category = IsAuthorisedValueCategory($category);
1230 Returns whether a given category name is a valid one
1232 =cut
1234 sub IsAuthorisedValueCategory {
1235 my $category = shift;
1236 my $query = '
1237 SELECT category
1238 FROM authorised_values
1239 WHERE BINARY category=?
1240 LIMIT 1
1242 my $sth = C4::Context->dbh->prepare($query);
1243 $sth->execute($category);
1244 $sth->fetchrow ? return 1
1245 : return 0;
1248 =head2 GetAuthorisedValueByCode
1250 $authorised_value = GetAuthorisedValueByCode( $category, $authvalcode, $opac );
1252 Return the lib attribute from authorised_values from the row identified
1253 by the passed category and code
1255 =cut
1257 sub GetAuthorisedValueByCode {
1258 my ( $category, $authvalcode, $opac ) = @_;
1260 my $field = $opac ? 'lib_opac' : 'lib';
1261 my $dbh = C4::Context->dbh;
1262 my $sth = $dbh->prepare("SELECT $field FROM authorised_values WHERE category=? AND authorised_value =?");
1263 $sth->execute( $category, $authvalcode );
1264 while ( my $data = $sth->fetchrow_hashref ) {
1265 return $data->{ $field };
1269 =head2 GetKohaAuthorisedValues
1271 Takes $kohafield, $fwcode as parameters.
1273 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1275 Returns hashref of Code => description
1277 Returns undef if no authorised value category is defined for the kohafield.
1279 =cut
1281 sub GetKohaAuthorisedValues {
1282 my ($kohafield,$fwcode,$opac) = @_;
1283 $fwcode='' unless $fwcode;
1284 my %values;
1285 my $dbh = C4::Context->dbh;
1286 my $avcode = GetAuthValCode($kohafield,$fwcode);
1287 if ($avcode) {
1288 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1289 $sth->execute($avcode);
1290 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1291 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1293 return \%values;
1294 } else {
1295 return;
1299 =head2 GetKohaAuthorisedValuesFromField
1301 Takes $field, $subfield, $fwcode as parameters.
1303 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1304 $subfield can be undefined
1306 Returns hashref of Code => description
1308 Returns undef if no authorised value category is defined for the given field and subfield
1310 =cut
1312 sub GetKohaAuthorisedValuesFromField {
1313 my ($field, $subfield, $fwcode,$opac) = @_;
1314 $fwcode='' unless $fwcode;
1315 my %values;
1316 my $dbh = C4::Context->dbh;
1317 my $avcode = GetAuthValCodeFromField($field, $subfield, $fwcode);
1318 if ($avcode) {
1319 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1320 $sth->execute($avcode);
1321 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1322 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1324 return \%values;
1325 } else {
1326 return;
1330 =head2 xml_escape
1332 my $escaped_string = C4::Koha::xml_escape($string);
1334 Convert &, <, >, ', and " in a string to XML entities
1336 =cut
1338 sub xml_escape {
1339 my $str = shift;
1340 return '' unless defined $str;
1341 $str =~ s/&/&amp;/g;
1342 $str =~ s/</&lt;/g;
1343 $str =~ s/>/&gt;/g;
1344 $str =~ s/'/&apos;/g;
1345 $str =~ s/"/&quot;/g;
1346 return $str;
1349 =head2 GetKohaAuthorisedValueLib
1351 Takes $category, $authorised_value as parameters.
1353 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1355 Returns authorised value description
1357 =cut
1359 sub GetKohaAuthorisedValueLib {
1360 my ($category,$authorised_value,$opac) = @_;
1361 my $value;
1362 my $dbh = C4::Context->dbh;
1363 my $sth = $dbh->prepare("select lib, lib_opac from authorised_values where category=? and authorised_value=?");
1364 $sth->execute($category,$authorised_value);
1365 my $data = $sth->fetchrow_hashref;
1366 $value = ($opac && $$data{'lib_opac'}) ? $$data{'lib_opac'} : $$data{'lib'};
1367 return $value;
1370 =head2 AddAuthorisedValue
1372 AddAuthorisedValue($category, $authorised_value, $lib, $lib_opac, $imageurl);
1374 Create a new authorised value.
1376 =cut
1378 sub AddAuthorisedValue {
1379 my ($category, $authorised_value, $lib, $lib_opac, $imageurl) = @_;
1381 my $dbh = C4::Context->dbh;
1382 my $query = qq{
1383 INSERT INTO authorised_values (category, authorised_value, lib, lib_opac, imageurl)
1384 VALUES (?,?,?,?,?)
1386 my $sth = $dbh->prepare($query);
1387 $sth->execute($category, $authorised_value, $lib, $lib_opac, $imageurl);
1390 =head2 display_marc_indicators
1392 my $display_form = C4::Koha::display_marc_indicators($field);
1394 C<$field> is a MARC::Field object
1396 Generate a display form of the indicators of a variable
1397 MARC field, replacing any blanks with '#'.
1399 =cut
1401 sub display_marc_indicators {
1402 my $field = shift;
1403 my $indicators = '';
1404 if ($field->tag() >= 10) {
1405 $indicators = $field->indicator(1) . $field->indicator(2);
1406 $indicators =~ s/ /#/g;
1408 return $indicators;
1411 sub GetNormalizedUPC {
1412 my ($record,$marcflavour) = @_;
1413 my (@fields,$upc);
1415 if ($marcflavour eq 'UNIMARC') {
1416 @fields = $record->field('072');
1417 foreach my $field (@fields) {
1418 my $upc = _normalize_match_point($field->subfield('a'));
1419 if ($upc ne '') {
1420 return $upc;
1425 else { # assume marc21 if not unimarc
1426 @fields = $record->field('024');
1427 foreach my $field (@fields) {
1428 my $indicator = $field->indicator(1);
1429 my $upc = _normalize_match_point($field->subfield('a'));
1430 if ($indicator == 1 and $upc ne '') {
1431 return $upc;
1437 # Normalizes and returns the first valid ISBN found in the record
1438 # ISBN13 are converted into ISBN10. This is required to get some book cover images.
1439 sub GetNormalizedISBN {
1440 my ($isbn,$record,$marcflavour) = @_;
1441 my @fields;
1442 if ($isbn) {
1443 # Koha attempts to store multiple ISBNs in biblioitems.isbn, separated by " | "
1444 # anything after " | " should be removed, along with the delimiter
1445 $isbn =~ s/(.*)( \| )(.*)/$1/;
1446 return _isbn_cleanup($isbn);
1448 return unless $record;
1450 if ($marcflavour eq 'UNIMARC') {
1451 @fields = $record->field('010');
1452 foreach my $field (@fields) {
1453 my $isbn = $field->subfield('a');
1454 if ($isbn) {
1455 return _isbn_cleanup($isbn);
1456 } else {
1457 return;
1461 else { # assume marc21 if not unimarc
1462 @fields = $record->field('020');
1463 foreach my $field (@fields) {
1464 $isbn = $field->subfield('a');
1465 if ($isbn) {
1466 return _isbn_cleanup($isbn);
1467 } else {
1468 return;
1474 sub GetNormalizedEAN {
1475 my ($record,$marcflavour) = @_;
1476 my (@fields,$ean);
1478 if ($marcflavour eq 'UNIMARC') {
1479 @fields = $record->field('073');
1480 foreach my $field (@fields) {
1481 $ean = _normalize_match_point($field->subfield('a'));
1482 if ($ean ne '') {
1483 return $ean;
1487 else { # assume marc21 if not unimarc
1488 @fields = $record->field('024');
1489 foreach my $field (@fields) {
1490 my $indicator = $field->indicator(1);
1491 $ean = _normalize_match_point($field->subfield('a'));
1492 if ($indicator == 3 and $ean ne '') {
1493 return $ean;
1498 sub GetNormalizedOCLCNumber {
1499 my ($record,$marcflavour) = @_;
1500 my (@fields,$oclc);
1502 if ($marcflavour eq 'UNIMARC') {
1503 # TODO: add UNIMARC fields
1505 else { # assume marc21 if not unimarc
1506 @fields = $record->field('035');
1507 foreach my $field (@fields) {
1508 $oclc = $field->subfield('a');
1509 if ($oclc =~ /OCoLC/) {
1510 $oclc =~ s/\(OCoLC\)//;
1511 return $oclc;
1512 } else {
1513 return;
1519 sub GetAuthvalueDropbox {
1520 my ( $authcat, $default ) = @_;
1521 my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
1522 my $dbh = C4::Context->dbh;
1524 my $query = qq{
1525 SELECT *
1526 FROM authorised_values
1528 $query .= qq{
1529 LEFT JOIN authorised_values_branches ON ( id = av_id )
1530 } if $branch_limit;
1531 $query .= qq{
1532 WHERE category = ?
1534 $query .= " AND ( branchcode = ? OR branchcode IS NULL )" if $branch_limit;
1535 $query .= " GROUP BY lib ORDER BY category, lib, lib_opac";
1536 my $sth = $dbh->prepare($query);
1537 $sth->execute( $authcat, $branch_limit ? $branch_limit : () );
1540 my $option_list = [];
1541 my @authorised_values = ( q{} );
1542 while (my $av = $sth->fetchrow_hashref) {
1543 push @{$option_list}, {
1544 value => $av->{authorised_value},
1545 label => $av->{lib},
1546 default => ($default eq $av->{authorised_value}),
1550 if ( @{$option_list} ) {
1551 return $option_list;
1553 return;
1557 =head2 GetDailyQuote($opts)
1559 Takes a hashref of options
1561 Currently supported options are:
1563 'id' An exact quote id
1564 'random' Select a random quote
1565 noop When no option is passed in, this sub will return the quote timestamped for the current day
1567 The function returns an anonymous hash following this format:
1570 'source' => 'source-of-quote',
1571 'timestamp' => 'timestamp-value',
1572 'text' => 'text-of-quote',
1573 'id' => 'quote-id'
1576 =cut
1578 # This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
1579 # at least for default option
1581 sub GetDailyQuote {
1582 my %opts = @_;
1583 my $dbh = C4::Context->dbh;
1584 my $query = '';
1585 my $sth = undef;
1586 my $quote = undef;
1587 if ($opts{'id'}) {
1588 $query = 'SELECT * FROM quotes WHERE id = ?';
1589 $sth = $dbh->prepare($query);
1590 $sth->execute($opts{'id'});
1591 $quote = $sth->fetchrow_hashref();
1593 elsif ($opts{'random'}) {
1594 # Fall through... we also return a random quote as a catch-all if all else fails
1596 else {
1597 $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp DESC LIMIT 0,1';
1598 $sth = $dbh->prepare($query);
1599 $sth->execute();
1600 $quote = $sth->fetchrow_hashref();
1602 unless ($quote) { # if there are not matches, choose a random quote
1603 # get a list of all available quote ids
1604 $sth = C4::Context->dbh->prepare('SELECT count(*) FROM quotes;');
1605 $sth->execute;
1606 my $range = ($sth->fetchrow_array)[0];
1607 # chose a random id within that range if there is more than one quote
1608 my $offset = int(rand($range));
1609 # grab it
1610 $query = 'SELECT * FROM quotes ORDER BY id LIMIT 1 OFFSET ?';
1611 $sth = C4::Context->dbh->prepare($query);
1612 # see http://www.perlmonks.org/?node_id=837422 for why
1613 # we're being verbose and using bind_param
1614 $sth->bind_param(1, $offset, SQL_INTEGER);
1615 $sth->execute();
1616 $quote = $sth->fetchrow_hashref();
1617 # update the timestamp for that quote
1618 $query = 'UPDATE quotes SET timestamp = ? WHERE id = ?';
1619 $sth = C4::Context->dbh->prepare($query);
1620 $sth->execute(
1621 DateTime::Format::MySQL->format_datetime( dt_from_string() ),
1622 $quote->{'id'}
1625 return $quote;
1628 sub _normalize_match_point {
1629 my $match_point = shift;
1630 (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
1631 $normalized_match_point =~ s/-//g;
1633 return $normalized_match_point;
1636 sub _isbn_cleanup {
1637 my ($isbn) = @_;
1638 return NormalizeISBN(
1640 isbn => $isbn,
1641 format => 'ISBN-10',
1642 strip_hyphens => 1,
1644 ) if $isbn;
1647 =head2 NormalizedISBN
1649 my $isbns = NormalizedISBN({
1650 isbn => $isbn,
1651 strip_hyphens => [0,1],
1652 format => ['ISBN-10', 'ISBN-13']
1655 Returns an isbn validated by Business::ISBN.
1656 Optionally strips hyphens and/or forces the isbn
1657 to be of the specified format.
1659 If the string cannot be validated as an isbn,
1660 it returns nothing.
1662 =cut
1664 sub NormalizeISBN {
1665 my ($params) = @_;
1667 my $string = $params->{isbn};
1668 my $strip_hyphens = $params->{strip_hyphens};
1669 my $format = $params->{format};
1671 return unless $string;
1673 my $isbn = Business::ISBN->new($string);
1675 if ( $isbn && $isbn->is_valid() ) {
1677 if ( $format eq 'ISBN-10' ) {
1678 $isbn = $isbn->as_isbn10();
1680 elsif ( $format eq 'ISBN-13' ) {
1681 $isbn = $isbn->as_isbn13();
1683 return unless $isbn;
1685 if ($strip_hyphens) {
1686 $string = $isbn->as_string( [] );
1687 } else {
1688 $string = $isbn->as_string();
1691 return $string;
1695 =head2 GetVariationsOfISBN
1697 my @isbns = GetVariationsOfISBN( $isbn );
1699 Returns a list of varations of the given isbn in
1700 both ISBN-10 and ISBN-13 formats, with and without
1701 hyphens.
1703 In a scalar context, the isbns are returned as a
1704 string delimited by ' | '.
1706 =cut
1708 sub GetVariationsOfISBN {
1709 my ($isbn) = @_;
1711 return unless $isbn;
1713 my @isbns;
1715 push( @isbns, NormalizeISBN({ isbn => $isbn }) );
1716 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10' }) );
1717 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13' }) );
1718 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10', strip_hyphens => 1 }) );
1719 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13', strip_hyphens => 1 }) );
1721 # Strip out any "empty" strings from the array
1722 @isbns = grep { defined($_) && $_ =~ /\S/ } @isbns;
1724 return wantarray ? @isbns : join( " | ", @isbns );
1727 =head2 GetVariationsOfISBNs
1729 my @isbns = GetVariationsOfISBNs( @isbns );
1731 Returns a list of varations of the given isbns in
1732 both ISBN-10 and ISBN-13 formats, with and without
1733 hyphens.
1735 In a scalar context, the isbns are returned as a
1736 string delimited by ' | '.
1738 =cut
1740 sub GetVariationsOfISBNs {
1741 my (@isbns) = @_;
1743 @isbns = map { GetVariationsOfISBN( $_ ) } @isbns;
1745 return wantarray ? @isbns : join( " | ", @isbns );
1748 =head2 IsKohaFieldLinked
1750 my $is_linked = IsKohaFieldLinked({
1751 kohafield => $kohafield,
1752 frameworkcode => $frameworkcode,
1755 Return 1 if the field is linked
1757 =cut
1759 sub IsKohaFieldLinked {
1760 my ( $params ) = @_;
1761 my $kohafield = $params->{kohafield};
1762 my $frameworkcode = $params->{frameworkcode} || '';
1763 my $dbh = C4::Context->dbh;
1764 my $is_linked = $dbh->selectcol_arrayref( q|
1765 SELECT COUNT(*)
1766 FROM marc_subfield_structure
1767 WHERE frameworkcode = ?
1768 AND kohafield = ?
1769 |,{}, $frameworkcode, $kohafield );
1770 return $is_linked->[0];
1775 __END__
1777 =head1 AUTHOR
1779 Koha Team
1781 =cut