Bug 9498 - Update encoding for Norwegian sample Z39.50 servers
[koha.git] / C4 / Koha.pm
blob6869ab07788a651ae64945cc3a2c4308eecc7ef1
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 Memoize;
29 use DateTime;
30 use DateTime::Format::MySQL;
31 use autouse 'Data::Dumper' => qw(Dumper);
33 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $DEBUG);
35 BEGIN {
36 $VERSION = 3.07.00.049;
37 require Exporter;
38 @ISA = qw(Exporter);
39 @EXPORT = qw(
40 &slashifyDate
41 &subfield_is_koha_internal_p
42 &GetPrinters &GetPrinter
43 &GetItemTypes &getitemtypeinfo
44 &GetCcodes
45 &GetSupportName &GetSupportList
46 &get_itemtypeinfos_of
47 &getframeworks &getframeworkinfo
48 &getauthtypes &getauthtype
49 &getallthemes
50 &getFacets
51 &displayServers
52 &getnbpages
53 &get_infos_of
54 &get_notforloan_label_of
55 &getitemtypeimagedir
56 &getitemtypeimagesrc
57 &getitemtypeimagelocation
58 &GetAuthorisedValues
59 &GetAuthorisedValueCategories
60 &GetKohaAuthorisedValues
61 &GetKohaAuthorisedValuesFromField
62 &GetKohaAuthorisedValueLib
63 &GetAuthorisedValueByCode
64 &GetKohaImageurlFromAuthorisedValues
65 &GetAuthValCode
66 &AddAuthorisedValue
67 &GetNormalizedUPC
68 &GetNormalizedISBN
69 &GetNormalizedEAN
70 &GetNormalizedOCLCNumber
71 &xml_escape
73 $DEBUG
75 $DEBUG = 0;
76 @EXPORT_OK = qw( GetDailyQuote );
79 # expensive functions
80 memoize('GetAuthorisedValues');
82 =head1 NAME
84 C4::Koha - Perl Module containing convenience functions for Koha scripts
86 =head1 SYNOPSIS
88 use C4::Koha;
90 =head1 DESCRIPTION
92 Koha.pm provides many functions for Koha scripts.
94 =head1 FUNCTIONS
96 =cut
98 =head2 slashifyDate
100 $slash_date = &slashifyDate($dash_date);
102 Takes a string of the form "DD-MM-YYYY" (or anything separated by
103 dashes), converts it to the form "YYYY/MM/DD", and returns the result.
105 =cut
107 sub slashifyDate {
109 # accepts a date of the form xx-xx-xx[xx] and returns it in the
110 # form xx/xx/xx[xx]
111 my @dateOut = split( '-', shift );
112 return ("$dateOut[2]/$dateOut[1]/$dateOut[0]");
115 # FIXME.. this should be moved to a MARC-specific module
116 sub subfield_is_koha_internal_p {
117 my ($subfield) = @_;
119 # We could match on 'lib' and 'tab' (and 'mandatory', & more to come!)
120 # But real MARC subfields are always single-character
121 # so it really is safer just to check the length
123 return length $subfield != 1;
126 =head2 GetSupportName
128 $itemtypename = &GetSupportName($codestring);
130 Returns a string with the name of the itemtype.
132 =cut
134 sub GetSupportName{
135 my ($codestring)=@_;
136 return if (! $codestring);
137 my $resultstring;
138 my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
139 if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') {
140 my $query = qq|
141 SELECT description
142 FROM itemtypes
143 WHERE itemtype=?
144 order by description
146 my $sth = C4::Context->dbh->prepare($query);
147 $sth->execute($codestring);
148 ($resultstring)=$sth->fetchrow;
149 return $resultstring;
150 } else {
151 my $sth =
152 C4::Context->dbh->prepare(
153 "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
155 $sth->execute( $advanced_search_types, $codestring );
156 my $data = $sth->fetchrow_hashref;
157 return $$data{'lib'};
161 =head2 GetSupportList
163 $itemtypes = &GetSupportList();
165 Returns an array ref containing informations about Support (since itemtype is rather a circulation code when item-level-itypes is used).
167 build a HTML select with the following code :
169 =head3 in PERL SCRIPT
171 my $itemtypes = GetSupportList();
172 $template->param(itemtypeloop => $itemtypes);
174 =head3 in TEMPLATE
176 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
177 <select name="itemtype">
178 <option value="">Default</option>
179 <!-- TMPL_LOOP name="itemtypeloop" -->
180 <option value="<!-- TMPL_VAR name="itemtype" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->> <!--TMPL_IF Name="imageurl"--><img alt="<!-- TMPL_VAR name="description" -->" src="<!--TMPL_VAR Name="imageurl"-->><!--TMPL_ELSE-->"<!-- TMPL_VAR name="description" --><!--/TMPL_IF--></option>
181 <!-- /TMPL_LOOP -->
182 </select>
183 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
184 <input type="submit" value="OK" class="button">
185 </form>
187 =cut
189 sub GetSupportList{
190 my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
191 if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') {
192 my $query = qq|
193 SELECT *
194 FROM itemtypes
195 order by description
197 my $sth = C4::Context->dbh->prepare($query);
198 $sth->execute;
199 return $sth->fetchall_arrayref({});
200 } else {
201 my $advsearchtypes = GetAuthorisedValues($advanced_search_types);
202 my @results= map {{itemtype=>$$_{authorised_value},description=>$$_{lib},imageurl=>$$_{imageurl}}} @$advsearchtypes;
203 return \@results;
206 =head2 GetItemTypes
208 $itemtypes = &GetItemTypes();
210 Returns information about existing itemtypes.
212 build a HTML select with the following code :
214 =head3 in PERL SCRIPT
216 my $itemtypes = GetItemTypes;
217 my @itemtypesloop;
218 foreach my $thisitemtype (sort keys %$itemtypes) {
219 my $selected = 1 if $thisitemtype eq $itemtype;
220 my %row =(value => $thisitemtype,
221 selected => $selected,
222 description => $itemtypes->{$thisitemtype}->{'description'},
224 push @itemtypesloop, \%row;
226 $template->param(itemtypeloop => \@itemtypesloop);
228 =head3 in TEMPLATE
230 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
231 <select name="itemtype">
232 <option value="">Default</option>
233 <!-- TMPL_LOOP name="itemtypeloop" -->
234 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="description" --></option>
235 <!-- /TMPL_LOOP -->
236 </select>
237 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
238 <input type="submit" value="OK" class="button">
239 </form>
241 =cut
243 sub GetItemTypes {
245 # returns a reference to a hash of references to itemtypes...
246 my %itemtypes;
247 my $dbh = C4::Context->dbh;
248 my $query = qq|
249 SELECT *
250 FROM itemtypes
252 my $sth = $dbh->prepare($query);
253 $sth->execute;
254 while ( my $IT = $sth->fetchrow_hashref ) {
255 $itemtypes{ $IT->{'itemtype'} } = $IT;
257 return ( \%itemtypes );
260 sub get_itemtypeinfos_of {
261 my @itemtypes = @_;
263 my $placeholders = join( ', ', map { '?' } @itemtypes );
264 my $query = <<"END_SQL";
265 SELECT itemtype,
266 description,
267 imageurl,
268 notforloan
269 FROM itemtypes
270 WHERE itemtype IN ( $placeholders )
271 END_SQL
273 return get_infos_of( $query, 'itemtype', undef, \@itemtypes );
276 # this is temporary until we separate collection codes and item types
277 sub GetCcodes {
278 my $count = 0;
279 my @results;
280 my $dbh = C4::Context->dbh;
281 my $sth =
282 $dbh->prepare(
283 "SELECT * FROM authorised_values ORDER BY authorised_value");
284 $sth->execute;
285 while ( my $data = $sth->fetchrow_hashref ) {
286 if ( $data->{category} eq "CCODE" ) {
287 $count++;
288 $results[$count] = $data;
290 #warn "data: $data";
293 $sth->finish;
294 return ( $count, @results );
297 =head2 getauthtypes
299 $authtypes = &getauthtypes();
301 Returns information about existing authtypes.
303 build a HTML select with the following code :
305 =head3 in PERL SCRIPT
307 my $authtypes = getauthtypes;
308 my @authtypesloop;
309 foreach my $thisauthtype (keys %$authtypes) {
310 my $selected = 1 if $thisauthtype eq $authtype;
311 my %row =(value => $thisauthtype,
312 selected => $selected,
313 authtypetext => $authtypes->{$thisauthtype}->{'authtypetext'},
315 push @authtypesloop, \%row;
317 $template->param(itemtypeloop => \@itemtypesloop);
319 =head3 in TEMPLATE
321 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
322 <select name="authtype">
323 <!-- TMPL_LOOP name="authtypeloop" -->
324 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="authtypetext" --></option>
325 <!-- /TMPL_LOOP -->
326 </select>
327 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
328 <input type="submit" value="OK" class="button">
329 </form>
332 =cut
334 sub getauthtypes {
336 # returns a reference to a hash of references to authtypes...
337 my %authtypes;
338 my $dbh = C4::Context->dbh;
339 my $sth = $dbh->prepare("select * from auth_types order by authtypetext");
340 $sth->execute;
341 while ( my $IT = $sth->fetchrow_hashref ) {
342 $authtypes{ $IT->{'authtypecode'} } = $IT;
344 return ( \%authtypes );
347 sub getauthtype {
348 my ($authtypecode) = @_;
350 # returns a reference to a hash of references to authtypes...
351 my %authtypes;
352 my $dbh = C4::Context->dbh;
353 my $sth = $dbh->prepare("select * from auth_types where authtypecode=?");
354 $sth->execute($authtypecode);
355 my $res = $sth->fetchrow_hashref;
356 return $res;
359 =head2 getframework
361 $frameworks = &getframework();
363 Returns information about existing frameworks
365 build a HTML select with the following code :
367 =head3 in PERL SCRIPT
369 my $frameworks = frameworks();
370 my @frameworkloop;
371 foreach my $thisframework (keys %$frameworks) {
372 my $selected = 1 if $thisframework eq $frameworkcode;
373 my %row =(value => $thisframework,
374 selected => $selected,
375 description => $frameworks->{$thisframework}->{'frameworktext'},
377 push @frameworksloop, \%row;
379 $template->param(frameworkloop => \@frameworksloop);
381 =head3 in TEMPLATE
383 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
384 <select name="frameworkcode">
385 <option value="">Default</option>
386 <!-- TMPL_LOOP name="frameworkloop" -->
387 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="frameworktext" --></option>
388 <!-- /TMPL_LOOP -->
389 </select>
390 <input type=text name=searchfield value="<!-- TMPL_VAR name="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 getframeworkinfo
411 $frameworkinfo = &getframeworkinfo($frameworkcode);
413 Returns information about an frameworkcode.
415 =cut
417 sub getframeworkinfo {
418 my ($frameworkcode) = @_;
419 my $dbh = C4::Context->dbh;
420 my $sth =
421 $dbh->prepare("select * from biblio_framework where frameworkcode=?");
422 $sth->execute($frameworkcode);
423 my $res = $sth->fetchrow_hashref;
424 return $res;
427 =head2 getitemtypeinfo
429 $itemtype = &getitemtypeinfo($itemtype, [$interface]);
431 Returns information about an itemtype. The optional $interface argument
432 sets which interface ('opac' or 'intranet') to return the imageurl for.
433 Defaults to intranet.
435 =cut
437 sub getitemtypeinfo {
438 my ($itemtype, $interface) = @_;
439 my $dbh = C4::Context->dbh;
440 my $sth = $dbh->prepare("select * from itemtypes where itemtype=?");
441 $sth->execute($itemtype);
442 my $res = $sth->fetchrow_hashref;
444 $res->{imageurl} = getitemtypeimagelocation( ( ( defined $interface && $interface eq 'opac' ) ? 'opac' : 'intranet' ), $res->{imageurl} );
446 return $res;
449 =head2 getitemtypeimagedir
451 my $directory = getitemtypeimagedir( 'opac' );
453 pass in 'opac' or 'intranet'. Defaults to 'opac'.
455 returns the full path to the appropriate directory containing images.
457 =cut
459 sub getitemtypeimagedir {
460 my $src = shift || 'opac';
461 if ($src eq 'intranet') {
462 return C4::Context->config('intrahtdocs') . '/' .C4::Context->preference('template') . '/img/itemtypeimg';
463 } else {
464 return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
468 sub getitemtypeimagesrc {
469 my $src = shift || 'opac';
470 if ($src eq 'intranet') {
471 return '/intranet-tmpl' . '/' . C4::Context->preference('template') . '/img/itemtypeimg';
472 } else {
473 return '/opac-tmpl' . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
477 sub getitemtypeimagelocation {
478 my ( $src, $image ) = @_;
480 return '' if ( !$image );
481 require URI::Split;
483 my $scheme = ( URI::Split::uri_split( $image ) )[0];
485 return $image if ( $scheme );
487 return getitemtypeimagesrc( $src ) . '/' . $image;
490 =head3 _getImagesFromDirectory
492 Find all of the image files in a directory in the filesystem
494 parameters: a directory name
496 returns: a list of images in that directory.
498 Notes: this does not traverse into subdirectories. See
499 _getSubdirectoryNames for help with that.
500 Images are assumed to be files with .gif or .png file extensions.
501 The image names returned do not have the directory name on them.
503 =cut
505 sub _getImagesFromDirectory {
506 my $directoryname = shift;
507 return unless defined $directoryname;
508 return unless -d $directoryname;
510 if ( opendir ( my $dh, $directoryname ) ) {
511 my @images = grep { /\.(gif|png)$/i } readdir( $dh );
512 closedir $dh;
513 @images = sort(@images);
514 return @images;
515 } else {
516 warn "unable to opendir $directoryname: $!";
517 return;
521 =head3 _getSubdirectoryNames
523 Find all of the directories in a directory in the filesystem
525 parameters: a directory name
527 returns: a list of subdirectories in that directory.
529 Notes: this does not traverse into subdirectories. Only the first
530 level of subdirectories are returned.
531 The directory names returned don't have the parent directory name on them.
533 =cut
535 sub _getSubdirectoryNames {
536 my $directoryname = shift;
537 return unless defined $directoryname;
538 return unless -d $directoryname;
540 if ( opendir ( my $dh, $directoryname ) ) {
541 my @directories = grep { -d File::Spec->catfile( $directoryname, $_ ) && ! ( /^\./ ) } readdir( $dh );
542 closedir $dh;
543 return @directories;
544 } else {
545 warn "unable to opendir $directoryname: $!";
546 return;
550 =head3 getImageSets
552 returns: a listref of hashrefs. Each hash represents another collection of images.
554 { imagesetname => 'npl', # the name of the image set (npl is the original one)
555 images => listref of image hashrefs
558 each image is represented by a hashref like this:
560 { KohaImage => 'npl/image.gif',
561 StaffImageUrl => '/intranet-tmpl/prog/img/itemtypeimg/npl/image.gif',
562 OpacImageURL => '/opac-tmpl/prog/itemtypeimg/npl/image.gif'
563 checked => 0 or 1: was this the image passed to this method?
564 Note: I'd like to remove this somehow.
567 =cut
569 sub getImageSets {
570 my %params = @_;
571 my $checked = $params{'checked'} || '';
573 my $paths = { staff => { filesystem => getitemtypeimagedir('intranet'),
574 url => getitemtypeimagesrc('intranet'),
576 opac => { filesystem => getitemtypeimagedir('opac'),
577 url => getitemtypeimagesrc('opac'),
581 my @imagesets = (); # list of hasrefs of image set data to pass to template
582 my @subdirectories = _getSubdirectoryNames( $paths->{'staff'}{'filesystem'} );
583 foreach my $imagesubdir ( @subdirectories ) {
584 warn $imagesubdir if $DEBUG;
585 my @imagelist = (); # hashrefs of image info
586 my @imagenames = _getImagesFromDirectory( File::Spec->catfile( $paths->{'staff'}{'filesystem'}, $imagesubdir ) );
587 my $imagesetactive = 0;
588 foreach my $thisimage ( @imagenames ) {
589 push( @imagelist,
590 { KohaImage => "$imagesubdir/$thisimage",
591 StaffImageUrl => join( '/', $paths->{'staff'}{'url'}, $imagesubdir, $thisimage ),
592 OpacImageUrl => join( '/', $paths->{'opac'}{'url'}, $imagesubdir, $thisimage ),
593 checked => "$imagesubdir/$thisimage" eq $checked ? 1 : 0,
596 $imagesetactive = 1 if "$imagesubdir/$thisimage" eq $checked;
598 push @imagesets, { imagesetname => $imagesubdir,
599 imagesetactive => $imagesetactive,
600 images => \@imagelist };
603 return \@imagesets;
606 =head2 GetPrinters
608 $printers = &GetPrinters();
609 @queues = keys %$printers;
611 Returns information about existing printer queues.
613 C<$printers> is a reference-to-hash whose keys are the print queues
614 defined in the printers table of the Koha database. The values are
615 references-to-hash, whose keys are the fields in the printers table.
617 =cut
619 sub GetPrinters {
620 my %printers;
621 my $dbh = C4::Context->dbh;
622 my $sth = $dbh->prepare("select * from printers");
623 $sth->execute;
624 while ( my $printer = $sth->fetchrow_hashref ) {
625 $printers{ $printer->{'printqueue'} } = $printer;
627 return ( \%printers );
630 =head2 GetPrinter
632 $printer = GetPrinter( $query, $printers );
634 =cut
636 sub GetPrinter {
637 my ( $query, $printers ) = @_; # get printer for this query from printers
638 my $printer = $query->param('printer');
639 my %cookie = $query->cookie('userenv');
640 ($printer) || ( $printer = $cookie{'printer'} ) || ( $printer = '' );
641 ( $printers->{$printer} ) || ( $printer = ( keys %$printers )[0] );
642 return $printer;
645 =head2 getnbpages
647 Returns the number of pages to display in a pagination bar, given the number
648 of items and the number of items per page.
650 =cut
652 sub getnbpages {
653 my ( $nb_items, $nb_items_per_page ) = @_;
655 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
658 =head2 getallthemes
660 (@themes) = &getallthemes('opac');
661 (@themes) = &getallthemes('intranet');
663 Returns an array of all available themes.
665 =cut
667 sub getallthemes {
668 my $type = shift;
669 my $htdocs;
670 my @themes;
671 if ( $type eq 'intranet' ) {
672 $htdocs = C4::Context->config('intrahtdocs');
674 else {
675 $htdocs = C4::Context->config('opachtdocs');
677 opendir D, "$htdocs";
678 my @dirlist = readdir D;
679 foreach my $directory (@dirlist) {
680 next if $directory eq 'lib';
681 -d "$htdocs/$directory/en" and push @themes, $directory;
683 return @themes;
686 sub getFacets {
687 my $facets;
688 if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
689 $facets = [
691 idx => 'su-to',
692 label => 'Topics',
693 tags => [ qw/ 600ab 601ab 602a 604at 605a 606ax 610a / ],
694 sep => ' - ',
697 idx => 'su-geo',
698 label => 'Places',
699 tags => [ qw/ 607a / ],
700 sep => ' - ',
703 idx => 'su-ut',
704 label => 'Titles',
705 tags => [ qw/ 500a 501a 503a / ],
706 sep => ', ',
709 idx => 'au',
710 label => 'Authors',
711 tags => [ qw/ 700ab 701ab 702ab / ],
712 sep => C4::Context->preference("UNIMARCAuthorsFacetsSeparator"),
715 idx => 'se',
716 label => 'Series',
717 tags => [ qw/ 225a / ],
718 sep => ', ',
722 my $library_facet;
723 unless ( C4::Context->preference("singleBranchMode") || GetBranchesCount() == 1 ) {
724 $library_facet = {
725 idx => 'branch',
726 label => 'Libraries',
727 tags => [ qw/ 995b / ],
729 } else {
730 $library_facet = {
731 idx => 'location',
732 label => 'Location',
733 tags => [ qw/ 995c / ],
736 push( @$facets, $library_facet );
738 else {
739 $facets = [
741 idx => 'su-to',
742 label => 'Topics',
743 tags => [ qw/ 650a / ],
744 sep => '--',
747 # idx => 'su-na',
748 # label => 'People and Organizations',
749 # tags => [ qw/ 600a 610a 611a / ],
750 # sep => 'a',
751 # },
753 idx => 'su-geo',
754 label => 'Places',
755 tags => [ qw/ 651a / ],
756 sep => '--',
759 idx => 'su-ut',
760 label => 'Titles',
761 tags => [ qw/ 630a / ],
762 sep => '--',
765 idx => 'au',
766 label => 'Authors',
767 tags => [ qw/ 100a 110a 700a / ],
768 sep => ', ',
771 idx => 'se',
772 label => 'Series',
773 tags => [ qw/ 440a 490a / ],
774 sep => ', ',
777 idx => 'itype',
778 label => 'ItemTypes',
779 tags => [ qw/ 952y 942c / ],
780 sep => ', ',
784 my $library_facet;
785 unless ( C4::Context->preference("singleBranchMode") || GetBranchesCount() == 1 ) {
786 $library_facet = {
787 idx => 'branch',
788 label => 'Libraries',
789 tags => [ qw / 952b / ],
791 } else {
792 $library_facet = {
793 idx => 'location',
794 label => 'Location',
795 tags => [ qw / 952c / ],
798 push( @$facets, $library_facet );
800 return $facets;
803 =head2 get_infos_of
805 Return a href where a key is associated to a href. You give a query,
806 the name of the key among the fields returned by the query. If you
807 also give as third argument the name of the value, the function
808 returns a href of scalar. The optional 4th argument is an arrayref of
809 items passed to the C<execute()> call. It is designed to bind
810 parameters to any placeholders in your SQL.
812 my $query = '
813 SELECT itemnumber,
814 notforloan,
815 barcode
816 FROM items
819 # generic href of any information on the item, href of href.
820 my $iteminfos_of = get_infos_of($query, 'itemnumber');
821 print $iteminfos_of->{$itemnumber}{barcode};
823 # specific information, href of scalar
824 my $barcode_of_item = get_infos_of($query, 'itemnumber', 'barcode');
825 print $barcode_of_item->{$itemnumber};
827 =cut
829 sub get_infos_of {
830 my ( $query, $key_name, $value_name, $bind_params ) = @_;
832 my $dbh = C4::Context->dbh;
834 my $sth = $dbh->prepare($query);
835 $sth->execute( @$bind_params );
837 my %infos_of;
838 while ( my $row = $sth->fetchrow_hashref ) {
839 if ( defined $value_name ) {
840 $infos_of{ $row->{$key_name} } = $row->{$value_name};
842 else {
843 $infos_of{ $row->{$key_name} } = $row;
846 $sth->finish;
848 return \%infos_of;
851 =head2 get_notforloan_label_of
853 my $notforloan_label_of = get_notforloan_label_of();
855 Each authorised value of notforloan (information available in items and
856 itemtypes) is link to a single label.
858 Returns a href where keys are authorised values and values are corresponding
859 labels.
861 foreach my $authorised_value (keys %{$notforloan_label_of}) {
862 printf(
863 "authorised_value: %s => %s\n",
864 $authorised_value,
865 $notforloan_label_of->{$authorised_value}
869 =cut
871 # FIXME - why not use GetAuthorisedValues ??
873 sub get_notforloan_label_of {
874 my $dbh = C4::Context->dbh;
876 my $query = '
877 SELECT authorised_value
878 FROM marc_subfield_structure
879 WHERE kohafield = \'items.notforloan\'
880 LIMIT 0, 1
882 my $sth = $dbh->prepare($query);
883 $sth->execute();
884 my ($statuscode) = $sth->fetchrow_array();
886 $query = '
887 SELECT lib,
888 authorised_value
889 FROM authorised_values
890 WHERE category = ?
892 $sth = $dbh->prepare($query);
893 $sth->execute($statuscode);
894 my %notforloan_label_of;
895 while ( my $row = $sth->fetchrow_hashref ) {
896 $notforloan_label_of{ $row->{authorised_value} } = $row->{lib};
898 $sth->finish;
900 return \%notforloan_label_of;
903 =head2 displayServers
905 my $servers = displayServers();
906 my $servers = displayServers( $position );
907 my $servers = displayServers( $position, $type );
909 displayServers returns a listref of hashrefs, each containing
910 information about available z3950 servers. Each hashref has a format
911 like:
914 'checked' => 'checked',
915 'encoding' => 'utf8',
916 'icon' => undef,
917 'id' => 'LIBRARY OF CONGRESS',
918 'label' => '',
919 'name' => 'server',
920 'opensearch' => '',
921 'value' => 'lx2.loc.gov:210/',
922 'zed' => 1,
925 =cut
927 sub displayServers {
928 my ( $position, $type ) = @_;
929 my $dbh = C4::Context->dbh;
931 my $strsth = 'SELECT * FROM z3950servers';
932 my @where_clauses;
933 my @bind_params;
935 if ($position) {
936 push @bind_params, $position;
937 push @where_clauses, ' position = ? ';
940 if ($type) {
941 push @bind_params, $type;
942 push @where_clauses, ' type = ? ';
945 # reassemble where clause from where clause pieces
946 if (@where_clauses) {
947 $strsth .= ' WHERE ' . join( ' AND ', @where_clauses );
950 my $rq = $dbh->prepare($strsth);
951 $rq->execute(@bind_params);
952 my @primaryserverloop;
954 while ( my $data = $rq->fetchrow_hashref ) {
955 push @primaryserverloop,
956 { label => $data->{description},
957 id => $data->{name},
958 name => "server",
959 value => $data->{host} . ":" . $data->{port} . "/" . $data->{database},
960 encoding => ( $data->{encoding} ? $data->{encoding} : "iso-5426" ),
961 checked => "checked",
962 icon => $data->{icon},
963 zed => $data->{type} eq 'zed',
964 opensearch => $data->{type} eq 'opensearch'
967 return \@primaryserverloop;
971 =head2 GetKohaImageurlFromAuthorisedValues
973 $authhorised_value = GetKohaImageurlFromAuthorisedValues( $category, $authvalcode );
975 Return the first url of the authorised value image represented by $lib.
977 =cut
979 sub GetKohaImageurlFromAuthorisedValues {
980 my ( $category, $lib ) = @_;
981 my $dbh = C4::Context->dbh;
982 my $sth = $dbh->prepare("SELECT imageurl FROM authorised_values WHERE category=? AND lib =?");
983 $sth->execute( $category, $lib );
984 while ( my $data = $sth->fetchrow_hashref ) {
985 return $data->{'imageurl'};
989 =head2 GetAuthValCode
991 $authvalcode = GetAuthValCode($kohafield,$frameworkcode);
993 =cut
995 sub GetAuthValCode {
996 my ($kohafield,$fwcode) = @_;
997 my $dbh = C4::Context->dbh;
998 $fwcode='' unless $fwcode;
999 my $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield=? and frameworkcode=?');
1000 $sth->execute($kohafield,$fwcode);
1001 my ($authvalcode) = $sth->fetchrow_array;
1002 return $authvalcode;
1005 =head2 GetAuthValCodeFromField
1007 $authvalcode = GetAuthValCodeFromField($field,$subfield,$frameworkcode);
1009 C<$subfield> can be undefined
1011 =cut
1013 sub GetAuthValCodeFromField {
1014 my ($field,$subfield,$fwcode) = @_;
1015 my $dbh = C4::Context->dbh;
1016 $fwcode='' unless $fwcode;
1017 my $sth;
1018 if (defined $subfield) {
1019 $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?');
1020 $sth->execute($field,$subfield,$fwcode);
1021 } else {
1022 $sth = $dbh->prepare('select authorised_value from marc_tag_structure where tagfield=? and frameworkcode=?');
1023 $sth->execute($field,$fwcode);
1025 my ($authvalcode) = $sth->fetchrow_array;
1026 return $authvalcode;
1029 =head2 GetAuthorisedValues
1031 $authvalues = GetAuthorisedValues([$category], [$selected]);
1033 This function returns all authorised values from the'authorised_value' table in a reference to array of hashrefs.
1035 C<$category> returns authorised values for just one category (optional).
1037 C<$opac> If set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1039 =cut
1041 sub GetAuthorisedValues {
1042 my ( $category, $selected, $opac ) = @_;
1043 my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
1044 my @results;
1045 my $dbh = C4::Context->dbh;
1046 my $query = qq{
1047 SELECT *
1048 FROM authorised_values
1050 $query .= qq{
1051 LEFT JOIN authorised_values_branches ON ( id = av_id )
1052 } if $branch_limit;
1053 my @where_strings;
1054 my @where_args;
1055 if($category) {
1056 push @where_strings, "category = ?";
1057 push @where_args, $category;
1059 if($branch_limit) {
1060 push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
1061 push @where_args, $branch_limit;
1063 if(@where_strings > 0) {
1064 $query .= " WHERE " . join(" AND ", @where_strings);
1066 $query .= " GROUP BY lib ORDER BY category, lib, lib_opac";
1068 my $sth = $dbh->prepare($query);
1070 $sth->execute( @where_args );
1071 while (my $data=$sth->fetchrow_hashref) {
1072 if ( defined $selected and $selected eq $data->{authorised_value} ) {
1073 $data->{selected} = 1;
1075 else {
1076 $data->{selected} = 0;
1079 if ($opac && $data->{lib_opac}) {
1080 $data->{lib} = $data->{lib_opac};
1082 push @results, $data;
1084 $sth->finish;
1085 return \@results;
1088 =head2 GetAuthorisedValueCategories
1090 $auth_categories = GetAuthorisedValueCategories();
1092 Return an arrayref of all of the available authorised
1093 value categories.
1095 =cut
1097 sub GetAuthorisedValueCategories {
1098 my $dbh = C4::Context->dbh;
1099 my $sth = $dbh->prepare("SELECT DISTINCT category FROM authorised_values ORDER BY category");
1100 $sth->execute;
1101 my @results;
1102 while (defined (my $category = $sth->fetchrow_array) ) {
1103 push @results, $category;
1105 return \@results;
1108 =head2 GetAuthorisedValueByCode
1110 $authhorised_value = GetAuthorisedValueByCode( $category, $authvalcode );
1112 Return the lib attribute from authorised_values from the row identified
1113 by the passed category and code
1115 =cut
1117 sub GetAuthorisedValueByCode {
1118 my ( $category, $authvalcode, $opac ) = @_;
1120 my $field = $opac ? 'lib_opac' : 'lib';
1121 my $dbh = C4::Context->dbh;
1122 my $sth = $dbh->prepare("SELECT $field FROM authorised_values WHERE category=? AND authorised_value =?");
1123 $sth->execute( $category, $authvalcode );
1124 while ( my $data = $sth->fetchrow_hashref ) {
1125 return $data->{ $field };
1129 =head2 GetKohaAuthorisedValues
1131 Takes $kohafield, $fwcode as parameters.
1133 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1135 Returns hashref of Code => description
1137 Returns undef if no authorised value category is defined for the kohafield.
1139 =cut
1141 sub GetKohaAuthorisedValues {
1142 my ($kohafield,$fwcode,$opac) = @_;
1143 $fwcode='' unless $fwcode;
1144 my %values;
1145 my $dbh = C4::Context->dbh;
1146 my $avcode = GetAuthValCode($kohafield,$fwcode);
1147 if ($avcode) {
1148 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1149 $sth->execute($avcode);
1150 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1151 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1153 return \%values;
1154 } else {
1155 return;
1159 =head2 GetKohaAuthorisedValuesFromField
1161 Takes $field, $subfield, $fwcode as parameters.
1163 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1164 $subfield can be undefined
1166 Returns hashref of Code => description
1168 Returns undef if no authorised value category is defined for the given field and subfield
1170 =cut
1172 sub GetKohaAuthorisedValuesFromField {
1173 my ($field, $subfield, $fwcode,$opac) = @_;
1174 $fwcode='' unless $fwcode;
1175 my %values;
1176 my $dbh = C4::Context->dbh;
1177 my $avcode = GetAuthValCodeFromField($field, $subfield, $fwcode);
1178 if ($avcode) {
1179 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1180 $sth->execute($avcode);
1181 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1182 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1184 return \%values;
1185 } else {
1186 return;
1190 =head2 xml_escape
1192 my $escaped_string = C4::Koha::xml_escape($string);
1194 Convert &, <, >, ', and " in a string to XML entities
1196 =cut
1198 sub xml_escape {
1199 my $str = shift;
1200 return '' unless defined $str;
1201 $str =~ s/&/&amp;/g;
1202 $str =~ s/</&lt;/g;
1203 $str =~ s/>/&gt;/g;
1204 $str =~ s/'/&apos;/g;
1205 $str =~ s/"/&quot;/g;
1206 return $str;
1209 =head2 GetKohaAuthorisedValueLib
1211 Takes $category, $authorised_value as parameters.
1213 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1215 Returns authorised value description
1217 =cut
1219 sub GetKohaAuthorisedValueLib {
1220 my ($category,$authorised_value,$opac) = @_;
1221 my $value;
1222 my $dbh = C4::Context->dbh;
1223 my $sth = $dbh->prepare("select lib, lib_opac from authorised_values where category=? and authorised_value=?");
1224 $sth->execute($category,$authorised_value);
1225 my $data = $sth->fetchrow_hashref;
1226 $value = ($opac && $$data{'lib_opac'}) ? $$data{'lib_opac'} : $$data{'lib'};
1227 return $value;
1230 =head2 AddAuthorisedValue
1232 AddAuthorisedValue($category, $authorised_value, $lib, $lib_opac, $imageurl);
1234 Create a new authorised value.
1236 =cut
1238 sub AddAuthorisedValue {
1239 my ($category, $authorised_value, $lib, $lib_opac, $imageurl) = @_;
1241 my $dbh = C4::Context->dbh;
1242 my $query = qq{
1243 INSERT INTO authorised_values (category, authorised_value, lib, lib_opac, imageurl)
1244 VALUES (?,?,?,?,?)
1246 my $sth = $dbh->prepare($query);
1247 $sth->execute($category, $authorised_value, $lib, $lib_opac, $imageurl);
1250 =head2 display_marc_indicators
1252 my $display_form = C4::Koha::display_marc_indicators($field);
1254 C<$field> is a MARC::Field object
1256 Generate a display form of the indicators of a variable
1257 MARC field, replacing any blanks with '#'.
1259 =cut
1261 sub display_marc_indicators {
1262 my $field = shift;
1263 my $indicators = '';
1264 if ($field->tag() >= 10) {
1265 $indicators = $field->indicator(1) . $field->indicator(2);
1266 $indicators =~ s/ /#/g;
1268 return $indicators;
1271 sub GetNormalizedUPC {
1272 my ($record,$marcflavour) = @_;
1273 my (@fields,$upc);
1275 if ($marcflavour eq 'UNIMARC') {
1276 @fields = $record->field('072');
1277 foreach my $field (@fields) {
1278 my $upc = _normalize_match_point($field->subfield('a'));
1279 if ($upc ne '') {
1280 return $upc;
1285 else { # assume marc21 if not unimarc
1286 @fields = $record->field('024');
1287 foreach my $field (@fields) {
1288 my $indicator = $field->indicator(1);
1289 my $upc = _normalize_match_point($field->subfield('a'));
1290 if ($indicator == 1 and $upc ne '') {
1291 return $upc;
1297 # Normalizes and returns the first valid ISBN found in the record
1298 # ISBN13 are converted into ISBN10. This is required to get some book cover images.
1299 sub GetNormalizedISBN {
1300 my ($isbn,$record,$marcflavour) = @_;
1301 my @fields;
1302 if ($isbn) {
1303 # Koha attempts to store multiple ISBNs in biblioitems.isbn, separated by " | "
1304 # anything after " | " should be removed, along with the delimiter
1305 $isbn =~ s/(.*)( \| )(.*)/$1/;
1306 return _isbn_cleanup($isbn);
1308 return unless $record;
1310 if ($marcflavour eq 'UNIMARC') {
1311 @fields = $record->field('010');
1312 foreach my $field (@fields) {
1313 my $isbn = $field->subfield('a');
1314 if ($isbn) {
1315 return _isbn_cleanup($isbn);
1316 } else {
1317 return;
1321 else { # assume marc21 if not unimarc
1322 @fields = $record->field('020');
1323 foreach my $field (@fields) {
1324 $isbn = $field->subfield('a');
1325 if ($isbn) {
1326 return _isbn_cleanup($isbn);
1327 } else {
1328 return;
1334 sub GetNormalizedEAN {
1335 my ($record,$marcflavour) = @_;
1336 my (@fields,$ean);
1338 if ($marcflavour eq 'UNIMARC') {
1339 @fields = $record->field('073');
1340 foreach my $field (@fields) {
1341 $ean = _normalize_match_point($field->subfield('a'));
1342 if ($ean ne '') {
1343 return $ean;
1347 else { # assume marc21 if not unimarc
1348 @fields = $record->field('024');
1349 foreach my $field (@fields) {
1350 my $indicator = $field->indicator(1);
1351 $ean = _normalize_match_point($field->subfield('a'));
1352 if ($indicator == 3 and $ean ne '') {
1353 return $ean;
1358 sub GetNormalizedOCLCNumber {
1359 my ($record,$marcflavour) = @_;
1360 my (@fields,$oclc);
1362 if ($marcflavour eq 'UNIMARC') {
1363 # TODO: add UNIMARC fields
1365 else { # assume marc21 if not unimarc
1366 @fields = $record->field('035');
1367 foreach my $field (@fields) {
1368 $oclc = $field->subfield('a');
1369 if ($oclc =~ /OCoLC/) {
1370 $oclc =~ s/\(OCoLC\)//;
1371 return $oclc;
1372 } else {
1373 return;
1379 =head2 GetDailyQuote($opts)
1381 Takes a hashref of options
1383 Currently supported options are:
1385 'id' An exact quote id
1386 'random' Select a random quote
1387 noop When no option is passed in, this sub will return the quote timestamped for the current day
1389 The function returns an anonymous hash following this format:
1392 'source' => 'source-of-quote',
1393 'timestamp' => 'timestamp-value',
1394 'text' => 'text-of-quote',
1395 'id' => 'quote-id'
1398 =cut
1400 # This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
1401 # at least for default option
1403 sub GetDailyQuote {
1404 my %opts = @_;
1405 my $dbh = C4::Context->dbh;
1406 my $query = '';
1407 my $sth = undef;
1408 my $quote = undef;
1409 if ($opts{'id'}) {
1410 $query = 'SELECT * FROM quotes WHERE id = ?';
1411 $sth = $dbh->prepare($query);
1412 $sth->execute($opts{'id'});
1413 $quote = $sth->fetchrow_hashref();
1415 elsif ($opts{'random'}) {
1416 # Fall through... we also return a random quote as a catch-all if all else fails
1418 else {
1419 $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp DESC LIMIT 0,1';
1420 $sth = $dbh->prepare($query);
1421 $sth->execute();
1422 $quote = $sth->fetchrow_hashref();
1424 unless ($quote) { # if there are not matches, choose a random quote
1425 # get a list of all available quote ids
1426 $sth = C4::Context->dbh->prepare('SELECT count(*) FROM quotes;');
1427 $sth->execute;
1428 my $range = ($sth->fetchrow_array)[0];
1429 if ($range > 1) {
1430 # chose a random id within that range if there is more than one quote
1431 my $id = int(rand($range));
1432 # grab it
1433 $query = 'SELECT * FROM quotes WHERE id = ?;';
1434 $sth = C4::Context->dbh->prepare($query);
1435 $sth->execute($id);
1437 else {
1438 $query = 'SELECT * FROM quotes;';
1439 $sth = C4::Context->dbh->prepare($query);
1440 $sth->execute();
1442 $quote = $sth->fetchrow_hashref();
1443 # update the timestamp for that quote
1444 $query = 'UPDATE quotes SET timestamp = ? WHERE id = ?';
1445 $sth = C4::Context->dbh->prepare($query);
1446 $sth->execute(DateTime::Format::MySQL->format_datetime(DateTime->now), $quote->{'id'});
1448 return $quote;
1451 sub _normalize_match_point {
1452 my $match_point = shift;
1453 (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
1454 $normalized_match_point =~ s/-//g;
1456 return $normalized_match_point;
1459 sub _isbn_cleanup {
1460 require Business::ISBN;
1461 my $isbn = Business::ISBN->new( $_[0] );
1462 if ( $isbn ) {
1463 $isbn = $isbn->as_isbn10 if $isbn->type eq 'ISBN13';
1464 if (defined $isbn) {
1465 return $isbn->as_string([]);
1468 return;
1473 __END__
1475 =head1 AUTHOR
1477 Koha Team
1479 =cut