More fixes to the shelves test
[koha.git] / C4 / Koha.pm
blob31bd6784db4774a411d378d702f7e0b3ceac4185
1 package C4::Koha;
3 # Copyright 2000-2002 Katipo Communications
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA 02111-1307 USA
21 use strict;
22 use C4::Context;
23 use C4::Output;
24 use URI::Split qw(uri_split);
25 use Memoize;
27 use vars qw($VERSION @ISA @EXPORT $DEBUG);
29 BEGIN {
30 $VERSION = 3.01;
31 require Exporter;
32 @ISA = qw(Exporter);
33 @EXPORT = qw(
34 &slashifyDate
35 &DisplayISBN
36 &subfield_is_koha_internal_p
37 &GetPrinters &GetPrinter
38 &GetItemTypes &getitemtypeinfo
39 &GetCcodes
40 &GetSupportName &GetSupportList
41 &get_itemtypeinfos_of
42 &getframeworks &getframeworkinfo
43 &getauthtypes &getauthtype
44 &getallthemes
45 &getFacets
46 &displayServers
47 &getnbpages
48 &get_infos_of
49 &get_notforloan_label_of
50 &getitemtypeimagedir
51 &getitemtypeimagesrc
52 &getitemtypeimagelocation
53 &GetAuthorisedValues
54 &GetAuthorisedValueCategories
55 &GetKohaAuthorisedValues
56 &GetAuthValCode
57 &GetNormalizedUPC
58 &GetNormalizedISBN
59 &GetNormalizedEAN
60 &GetNormalizedOCLCNumber
62 $DEBUG
64 $DEBUG = 0;
67 # expensive functions
68 memoize('GetAuthorisedValues');
70 =head1 NAME
72 C4::Koha - Perl Module containing convenience functions for Koha scripts
74 =head1 SYNOPSIS
76 use C4::Koha;
79 =head1 DESCRIPTION
81 Koha.pm provides many functions for Koha scripts.
83 =head1 FUNCTIONS
85 =cut
87 =head2 slashifyDate
89 $slash_date = &slashifyDate($dash_date);
91 Takes a string of the form "DD-MM-YYYY" (or anything separated by
92 dashes), converts it to the form "YYYY/MM/DD", and returns the result.
94 =cut
96 sub slashifyDate {
98 # accepts a date of the form xx-xx-xx[xx] and returns it in the
99 # form xx/xx/xx[xx]
100 my @dateOut = split( '-', shift );
101 return ("$dateOut[2]/$dateOut[1]/$dateOut[0]");
105 =head2 DisplayISBN
107 my $string = DisplayISBN( $isbn );
109 =cut
111 sub DisplayISBN {
112 my ($isbn) = @_;
113 if (length ($isbn)<13){
114 my $seg1;
115 if ( substr( $isbn, 0, 1 ) <= 7 ) {
116 $seg1 = substr( $isbn, 0, 1 );
118 elsif ( substr( $isbn, 0, 2 ) <= 94 ) {
119 $seg1 = substr( $isbn, 0, 2 );
121 elsif ( substr( $isbn, 0, 3 ) <= 995 ) {
122 $seg1 = substr( $isbn, 0, 3 );
124 elsif ( substr( $isbn, 0, 4 ) <= 9989 ) {
125 $seg1 = substr( $isbn, 0, 4 );
127 else {
128 $seg1 = substr( $isbn, 0, 5 );
130 my $x = substr( $isbn, length($seg1) );
131 my $seg2;
132 if ( substr( $x, 0, 2 ) <= 19 ) {
134 # if(sTmp2 < 10) sTmp2 = "0" sTmp2;
135 $seg2 = substr( $x, 0, 2 );
137 elsif ( substr( $x, 0, 3 ) <= 699 ) {
138 $seg2 = substr( $x, 0, 3 );
140 elsif ( substr( $x, 0, 4 ) <= 8399 ) {
141 $seg2 = substr( $x, 0, 4 );
143 elsif ( substr( $x, 0, 5 ) <= 89999 ) {
144 $seg2 = substr( $x, 0, 5 );
146 elsif ( substr( $x, 0, 6 ) <= 9499999 ) {
147 $seg2 = substr( $x, 0, 6 );
149 else {
150 $seg2 = substr( $x, 0, 7 );
152 my $seg3 = substr( $x, length($seg2) );
153 $seg3 = substr( $seg3, 0, length($seg3) - 1 );
154 my $seg4 = substr( $x, -1, 1 );
155 return "$seg1-$seg2-$seg3-$seg4";
156 } else {
157 my $seg1;
158 $seg1 = substr( $isbn, 0, 3 );
159 my $seg2;
160 if ( substr( $isbn, 3, 1 ) <= 7 ) {
161 $seg2 = substr( $isbn, 3, 1 );
163 elsif ( substr( $isbn, 3, 2 ) <= 94 ) {
164 $seg2 = substr( $isbn, 3, 2 );
166 elsif ( substr( $isbn, 3, 3 ) <= 995 ) {
167 $seg2 = substr( $isbn, 3, 3 );
169 elsif ( substr( $isbn, 3, 4 ) <= 9989 ) {
170 $seg2 = substr( $isbn, 3, 4 );
172 else {
173 $seg2 = substr( $isbn, 3, 5 );
175 my $x = substr( $isbn, length($seg2) +3);
176 my $seg3;
177 if ( substr( $x, 0, 2 ) <= 19 ) {
179 # if(sTmp2 < 10) sTmp2 = "0" sTmp2;
180 $seg3 = substr( $x, 0, 2 );
182 elsif ( substr( $x, 0, 3 ) <= 699 ) {
183 $seg3 = substr( $x, 0, 3 );
185 elsif ( substr( $x, 0, 4 ) <= 8399 ) {
186 $seg3 = substr( $x, 0, 4 );
188 elsif ( substr( $x, 0, 5 ) <= 89999 ) {
189 $seg3 = substr( $x, 0, 5 );
191 elsif ( substr( $x, 0, 6 ) <= 9499999 ) {
192 $seg3 = substr( $x, 0, 6 );
194 else {
195 $seg3 = substr( $x, 0, 7 );
197 my $seg4 = substr( $x, length($seg3) );
198 $seg4 = substr( $seg4, 0, length($seg4) - 1 );
199 my $seg5 = substr( $x, -1, 1 );
200 return "$seg1-$seg2-$seg3-$seg4-$seg5";
204 # FIXME.. this should be moved to a MARC-specific module
205 sub subfield_is_koha_internal_p ($) {
206 my ($subfield) = @_;
208 # We could match on 'lib' and 'tab' (and 'mandatory', & more to come!)
209 # But real MARC subfields are always single-character
210 # so it really is safer just to check the length
212 return length $subfield != 1;
215 =head2 GetSupportName
217 $itemtypename = &GetSupportName($codestring);
219 Returns a string with the name of the itemtype.
222 =cut
224 sub GetSupportName{
225 my ($codestring)=@_;
226 return if (! $codestring);
227 my $resultstring;
228 my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
229 if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') {
230 my $query = qq|
231 SELECT description
232 FROM itemtypes
233 WHERE itemtype=?
234 order by description
236 my $sth = C4::Context->dbh->prepare($query);
237 $sth->execute($codestring);
238 ($resultstring)=$sth->fetchrow;
239 return $resultstring;
240 } else {
241 my $sth =
242 C4::Context->dbh->prepare(
243 "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
245 $sth->execute( $advanced_search_types, $codestring );
246 my $data = $sth->fetchrow_hashref;
247 return $$data{'lib'};
251 =head2 GetSupportList
253 $itemtypes = &GetSupportList();
255 Returns an array ref containing informations about Support (since itemtype is rather a circulation code when item-level-itypes is used).
257 build a HTML select with the following code :
259 =head3 in PERL SCRIPT
261 my $itemtypes = GetSupportList();
262 $template->param(itemtypeloop => $itemtypes);
264 =head3 in TEMPLATE
266 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
267 <select name="itemtype">
268 <option value="">Default</option>
269 <!-- TMPL_LOOP name="itemtypeloop" -->
270 <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>
271 <!-- /TMPL_LOOP -->
272 </select>
273 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
274 <input type="submit" value="OK" class="button">
275 </form>
277 =cut
279 sub GetSupportList{
280 my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
281 if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') {
282 my $query = qq|
283 SELECT *
284 FROM itemtypes
285 order by description
287 my $sth = C4::Context->dbh->prepare($query);
288 $sth->execute;
289 return $sth->fetchall_arrayref({});
290 } else {
291 my $advsearchtypes = GetAuthorisedValues($advanced_search_types);
292 my @results= map {{itemtype=>$$_{authorised_value},description=>$$_{lib},imageurl=>$$_{imageurl}}} @$advsearchtypes;
293 return \@results;
296 =head2 GetItemTypes
298 $itemtypes = &GetItemTypes();
300 Returns information about existing itemtypes.
302 build a HTML select with the following code :
304 =head3 in PERL SCRIPT
306 my $itemtypes = GetItemTypes;
307 my @itemtypesloop;
308 foreach my $thisitemtype (sort keys %$itemtypes) {
309 my $selected = 1 if $thisitemtype eq $itemtype;
310 my %row =(value => $thisitemtype,
311 selected => $selected,
312 description => $itemtypes->{$thisitemtype}->{'description'},
314 push @itemtypesloop, \%row;
316 $template->param(itemtypeloop => \@itemtypesloop);
318 =head3 in TEMPLATE
320 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
321 <select name="itemtype">
322 <option value="">Default</option>
323 <!-- TMPL_LOOP name="itemtypeloop" -->
324 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="description" --></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>
331 =cut
333 sub GetItemTypes {
335 # returns a reference to a hash of references to itemtypes...
336 my %itemtypes;
337 my $dbh = C4::Context->dbh;
338 my $query = qq|
339 SELECT *
340 FROM itemtypes
342 my $sth = $dbh->prepare($query);
343 $sth->execute;
344 while ( my $IT = $sth->fetchrow_hashref ) {
345 $itemtypes{ $IT->{'itemtype'} } = $IT;
347 return ( \%itemtypes );
350 sub get_itemtypeinfos_of {
351 my @itemtypes = @_;
353 my $placeholders = join( ', ', map { '?' } @itemtypes );
354 my $query = <<"END_SQL";
355 SELECT itemtype,
356 description,
357 imageurl,
358 notforloan
359 FROM itemtypes
360 WHERE itemtype IN ( $placeholders )
361 END_SQL
363 return get_infos_of( $query, 'itemtype', undef, \@itemtypes );
366 # this is temporary until we separate collection codes and item types
367 sub GetCcodes {
368 my $count = 0;
369 my @results;
370 my $dbh = C4::Context->dbh;
371 my $sth =
372 $dbh->prepare(
373 "SELECT * FROM authorised_values ORDER BY authorised_value");
374 $sth->execute;
375 while ( my $data = $sth->fetchrow_hashref ) {
376 if ( $data->{category} eq "CCODE" ) {
377 $count++;
378 $results[$count] = $data;
380 #warn "data: $data";
383 $sth->finish;
384 return ( $count, @results );
387 =head2 getauthtypes
389 $authtypes = &getauthtypes();
391 Returns information about existing authtypes.
393 build a HTML select with the following code :
395 =head3 in PERL SCRIPT
397 my $authtypes = getauthtypes;
398 my @authtypesloop;
399 foreach my $thisauthtype (keys %$authtypes) {
400 my $selected = 1 if $thisauthtype eq $authtype;
401 my %row =(value => $thisauthtype,
402 selected => $selected,
403 authtypetext => $authtypes->{$thisauthtype}->{'authtypetext'},
405 push @authtypesloop, \%row;
407 $template->param(itemtypeloop => \@itemtypesloop);
409 =head3 in TEMPLATE
411 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
412 <select name="authtype">
413 <!-- TMPL_LOOP name="authtypeloop" -->
414 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="authtypetext" --></option>
415 <!-- /TMPL_LOOP -->
416 </select>
417 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
418 <input type="submit" value="OK" class="button">
419 </form>
422 =cut
424 sub getauthtypes {
426 # returns a reference to a hash of references to authtypes...
427 my %authtypes;
428 my $dbh = C4::Context->dbh;
429 my $sth = $dbh->prepare("select * from auth_types order by authtypetext");
430 $sth->execute;
431 while ( my $IT = $sth->fetchrow_hashref ) {
432 $authtypes{ $IT->{'authtypecode'} } = $IT;
434 return ( \%authtypes );
437 sub getauthtype {
438 my ($authtypecode) = @_;
440 # returns a reference to a hash of references to authtypes...
441 my %authtypes;
442 my $dbh = C4::Context->dbh;
443 my $sth = $dbh->prepare("select * from auth_types where authtypecode=?");
444 $sth->execute($authtypecode);
445 my $res = $sth->fetchrow_hashref;
446 return $res;
449 =head2 getframework
451 $frameworks = &getframework();
453 Returns information about existing frameworks
455 build a HTML select with the following code :
457 =head3 in PERL SCRIPT
459 my $frameworks = frameworks();
460 my @frameworkloop;
461 foreach my $thisframework (keys %$frameworks) {
462 my $selected = 1 if $thisframework eq $frameworkcode;
463 my %row =(value => $thisframework,
464 selected => $selected,
465 description => $frameworks->{$thisframework}->{'frameworktext'},
467 push @frameworksloop, \%row;
469 $template->param(frameworkloop => \@frameworksloop);
471 =head3 in TEMPLATE
473 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
474 <select name="frameworkcode">
475 <option value="">Default</option>
476 <!-- TMPL_LOOP name="frameworkloop" -->
477 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="frameworktext" --></option>
478 <!-- /TMPL_LOOP -->
479 </select>
480 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
481 <input type="submit" value="OK" class="button">
482 </form>
485 =cut
487 sub getframeworks {
489 # returns a reference to a hash of references to branches...
490 my %itemtypes;
491 my $dbh = C4::Context->dbh;
492 my $sth = $dbh->prepare("select * from biblio_framework");
493 $sth->execute;
494 while ( my $IT = $sth->fetchrow_hashref ) {
495 $itemtypes{ $IT->{'frameworkcode'} } = $IT;
497 return ( \%itemtypes );
500 =head2 getframeworkinfo
502 $frameworkinfo = &getframeworkinfo($frameworkcode);
504 Returns information about an frameworkcode.
506 =cut
508 sub getframeworkinfo {
509 my ($frameworkcode) = @_;
510 my $dbh = C4::Context->dbh;
511 my $sth =
512 $dbh->prepare("select * from biblio_framework where frameworkcode=?");
513 $sth->execute($frameworkcode);
514 my $res = $sth->fetchrow_hashref;
515 return $res;
518 =head2 getitemtypeinfo
520 $itemtype = &getitemtype($itemtype);
522 Returns information about an itemtype.
524 =cut
526 sub getitemtypeinfo {
527 my ($itemtype) = @_;
528 my $dbh = C4::Context->dbh;
529 my $sth = $dbh->prepare("select * from itemtypes where itemtype=?");
530 $sth->execute($itemtype);
531 my $res = $sth->fetchrow_hashref;
533 $res->{imageurl} = getitemtypeimagelocation( 'intranet', $res->{imageurl} );
535 return $res;
538 =head2 getitemtypeimagedir
540 =over
542 =item 4
544 my $directory = getitemtypeimagedir( 'opac' );
546 pass in 'opac' or 'intranet'. Defaults to 'opac'.
548 returns the full path to the appropriate directory containing images.
550 =back
552 =cut
554 sub getitemtypeimagedir {
555 my $src = shift || 'opac';
556 if ($src eq 'intranet') {
557 return C4::Context->config('intrahtdocs') . '/' .C4::Context->preference('template') . '/img/itemtypeimg';
558 } else {
559 return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('template') . '/itemtypeimg';
563 sub getitemtypeimagesrc {
564 my $src = shift || 'opac';
565 if ($src eq 'intranet') {
566 return '/intranet-tmpl' . '/' . C4::Context->preference('template') . '/img/itemtypeimg';
567 } else {
568 return '/opac-tmpl' . '/' . C4::Context->preference('template') . '/itemtypeimg';
572 sub getitemtypeimagelocation($$) {
573 my ( $src, $image ) = @_;
575 return '' if ( !$image );
577 my $scheme = ( uri_split( $image ) )[0];
579 return $image if ( $scheme );
581 return getitemtypeimagesrc( $src ) . '/' . $image;
584 =head3 _getImagesFromDirectory
586 Find all of the image files in a directory in the filesystem
588 parameters:
589 a directory name
591 returns: a list of images in that directory.
593 Notes: this does not traverse into subdirectories. See
594 _getSubdirectoryNames for help with that.
595 Images are assumed to be files with .gif or .png file extensions.
596 The image names returned do not have the directory name on them.
598 =cut
600 sub _getImagesFromDirectory {
601 my $directoryname = shift;
602 return unless defined $directoryname;
603 return unless -d $directoryname;
605 if ( opendir ( my $dh, $directoryname ) ) {
606 my @images = grep { /\.(gif|png)$/i } readdir( $dh );
607 closedir $dh;
608 return @images;
609 } else {
610 warn "unable to opendir $directoryname: $!";
611 return;
615 =head3 _getSubdirectoryNames
617 Find all of the directories in a directory in the filesystem
619 parameters:
620 a directory name
622 returns: a list of subdirectories in that directory.
624 Notes: this does not traverse into subdirectories. Only the first
625 level of subdirectories are returned.
626 The directory names returned don't have the parent directory name
627 on them.
629 =cut
631 sub _getSubdirectoryNames {
632 my $directoryname = shift;
633 return unless defined $directoryname;
634 return unless -d $directoryname;
636 if ( opendir ( my $dh, $directoryname ) ) {
637 my @directories = grep { -d File::Spec->catfile( $directoryname, $_ ) && ! ( /^\./ ) } readdir( $dh );
638 closedir $dh;
639 return @directories;
640 } else {
641 warn "unable to opendir $directoryname: $!";
642 return;
646 =head3 getImageSets
648 returns: a listref of hashrefs. Each hash represents another collection of images.
649 { imagesetname => 'npl', # the name of the image set (npl is the original one)
650 images => listref of image hashrefs
653 each image is represented by a hashref like this:
654 { KohaImage => 'npl/image.gif',
655 StaffImageUrl => '/intranet-tmpl/prog/img/itemtypeimg/npl/image.gif',
656 OpacImageURL => '/opac-tmpl/prog/itemtypeimg/npl/image.gif'
657 checked => 0 or 1: was this the image passed to this method?
658 Note: I'd like to remove this somehow.
661 =cut
663 sub getImageSets {
664 my %params = @_;
665 my $checked = $params{'checked'} || '';
667 my $paths = { staff => { filesystem => getitemtypeimagedir('intranet'),
668 url => getitemtypeimagesrc('intranet'),
670 opac => { filesystem => getitemtypeimagedir('opac'),
671 url => getitemtypeimagesrc('opac'),
675 my @imagesets = (); # list of hasrefs of image set data to pass to template
676 my @subdirectories = _getSubdirectoryNames( $paths->{'staff'}{'filesystem'} );
678 foreach my $imagesubdir ( @subdirectories ) {
679 my @imagelist = (); # hashrefs of image info
680 my @imagenames = _getImagesFromDirectory( File::Spec->catfile( $paths->{'staff'}{'filesystem'}, $imagesubdir ) );
681 foreach my $thisimage ( @imagenames ) {
682 push( @imagelist,
683 { KohaImage => "$imagesubdir/$thisimage",
684 StaffImageUrl => join( '/', $paths->{'staff'}{'url'}, $imagesubdir, $thisimage ),
685 OpacImageUrl => join( '/', $paths->{'opac'}{'url'}, $imagesubdir, $thisimage ),
686 checked => "$imagesubdir/$thisimage" eq $checked ? 1 : 0,
690 push @imagesets, { imagesetname => $imagesubdir,
691 images => \@imagelist };
694 return \@imagesets;
697 =head2 GetPrinters
699 $printers = &GetPrinters();
700 @queues = keys %$printers;
702 Returns information about existing printer queues.
704 C<$printers> is a reference-to-hash whose keys are the print queues
705 defined in the printers table of the Koha database. The values are
706 references-to-hash, whose keys are the fields in the printers table.
708 =cut
710 sub GetPrinters {
711 my %printers;
712 my $dbh = C4::Context->dbh;
713 my $sth = $dbh->prepare("select * from printers");
714 $sth->execute;
715 while ( my $printer = $sth->fetchrow_hashref ) {
716 $printers{ $printer->{'printqueue'} } = $printer;
718 return ( \%printers );
721 =head2 GetPrinter
723 $printer = GetPrinter( $query, $printers );
725 =cut
727 sub GetPrinter ($$) {
728 my ( $query, $printers ) = @_; # get printer for this query from printers
729 my $printer = $query->param('printer');
730 my %cookie = $query->cookie('userenv');
731 ($printer) || ( $printer = $cookie{'printer'} ) || ( $printer = '' );
732 ( $printers->{$printer} ) || ( $printer = ( keys %$printers )[0] );
733 return $printer;
736 =head2 getnbpages
738 Returns the number of pages to display in a pagination bar, given the number
739 of items and the number of items per page.
741 =cut
743 sub getnbpages {
744 my ( $nb_items, $nb_items_per_page ) = @_;
746 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
749 =head2 getallthemes
751 (@themes) = &getallthemes('opac');
752 (@themes) = &getallthemes('intranet');
754 Returns an array of all available themes.
756 =cut
758 sub getallthemes {
759 my $type = shift;
760 my $htdocs;
761 my @themes;
762 if ( $type eq 'intranet' ) {
763 $htdocs = C4::Context->config('intrahtdocs');
765 else {
766 $htdocs = C4::Context->config('opachtdocs');
768 opendir D, "$htdocs";
769 my @dirlist = readdir D;
770 foreach my $directory (@dirlist) {
771 -d "$htdocs/$directory/en" and push @themes, $directory;
773 return @themes;
776 sub getFacets {
777 my $facets;
778 if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
779 $facets = [
781 link_value => 'su-to',
782 label_value => 'Topics',
783 tags =>
784 [ '600', '601', '602', '603', '604', '605', '606', '610' ],
785 subfield => 'a',
788 link_value => 'su-geo',
789 label_value => 'Places',
790 tags => ['651'],
791 subfield => 'a',
794 link_value => 'su-ut',
795 label_value => 'Titles',
796 tags => [ '500', '501', '502', '503', '504', ],
797 subfield => 'a',
800 link_value => 'au',
801 label_value => 'Authors',
802 tags => [ '700', '701', '702', ],
803 subfield => 'a',
806 link_value => 'se',
807 label_value => 'Series',
808 tags => ['225'],
809 subfield => 'a',
813 my $library_facet;
815 $library_facet = {
816 link_value => 'branch',
817 label_value => 'Libraries',
818 tags => [ '995', ],
819 subfield => 'b',
820 expanded => '1',
822 push @$facets, $library_facet unless C4::Context->preference("singleBranchMode");
824 else {
825 $facets = [
827 link_value => 'su-to',
828 label_value => 'Topics',
829 tags => ['650'],
830 subfield => 'a',
834 # link_value => 'su-na',
835 # label_value => 'People and Organizations',
836 # tags => ['600', '610', '611'],
837 # subfield => 'a',
838 # },
840 link_value => 'su-geo',
841 label_value => 'Places',
842 tags => ['651'],
843 subfield => 'a',
846 link_value => 'su-ut',
847 label_value => 'Titles',
848 tags => ['630'],
849 subfield => 'a',
852 link_value => 'au',
853 label_value => 'Authors',
854 tags => [ '100', '110', '700', ],
855 subfield => 'a',
858 link_value => 'se',
859 label_value => 'Series',
860 tags => [ '440', '490', ],
861 subfield => 'a',
864 my $library_facet;
865 $library_facet = {
866 link_value => 'branch',
867 label_value => 'Libraries',
868 tags => [ '952', ],
869 subfield => 'b',
870 expanded => '1',
872 push @$facets, $library_facet unless C4::Context->preference("singleBranchMode");
874 return $facets;
877 =head2 get_infos_of
879 Return a href where a key is associated to a href. You give a query,
880 the name of the key among the fields returned by the query. If you
881 also give as third argument the name of the value, the function
882 returns a href of scalar. The optional 4th argument is an arrayref of
883 items passed to the C<execute()> call. It is designed to bind
884 parameters to any placeholders in your SQL.
886 my $query = '
887 SELECT itemnumber,
888 notforloan,
889 barcode
890 FROM items
893 # generic href of any information on the item, href of href.
894 my $iteminfos_of = get_infos_of($query, 'itemnumber');
895 print $iteminfos_of->{$itemnumber}{barcode};
897 # specific information, href of scalar
898 my $barcode_of_item = get_infos_of($query, 'itemnumber', 'barcode');
899 print $barcode_of_item->{$itemnumber};
901 =cut
903 sub get_infos_of {
904 my ( $query, $key_name, $value_name, $bind_params ) = @_;
906 my $dbh = C4::Context->dbh;
908 my $sth = $dbh->prepare($query);
909 $sth->execute( @$bind_params );
911 my %infos_of;
912 while ( my $row = $sth->fetchrow_hashref ) {
913 if ( defined $value_name ) {
914 $infos_of{ $row->{$key_name} } = $row->{$value_name};
916 else {
917 $infos_of{ $row->{$key_name} } = $row;
920 $sth->finish;
922 return \%infos_of;
925 =head2 get_notforloan_label_of
927 my $notforloan_label_of = get_notforloan_label_of();
929 Each authorised value of notforloan (information available in items and
930 itemtypes) is link to a single label.
932 Returns a href where keys are authorised values and values are corresponding
933 labels.
935 foreach my $authorised_value (keys %{$notforloan_label_of}) {
936 printf(
937 "authorised_value: %s => %s\n",
938 $authorised_value,
939 $notforloan_label_of->{$authorised_value}
943 =cut
945 # FIXME - why not use GetAuthorisedValues ??
947 sub get_notforloan_label_of {
948 my $dbh = C4::Context->dbh;
950 my $query = '
951 SELECT authorised_value
952 FROM marc_subfield_structure
953 WHERE kohafield = \'items.notforloan\'
954 LIMIT 0, 1
956 my $sth = $dbh->prepare($query);
957 $sth->execute();
958 my ($statuscode) = $sth->fetchrow_array();
960 $query = '
961 SELECT lib,
962 authorised_value
963 FROM authorised_values
964 WHERE category = ?
966 $sth = $dbh->prepare($query);
967 $sth->execute($statuscode);
968 my %notforloan_label_of;
969 while ( my $row = $sth->fetchrow_hashref ) {
970 $notforloan_label_of{ $row->{authorised_value} } = $row->{lib};
972 $sth->finish;
974 return \%notforloan_label_of;
977 =head2 displayServers
979 =over 4
981 my $servers = displayServers();
983 my $servers = displayServers( $position );
985 my $servers = displayServers( $position, $type );
987 =back
989 displayServers returns a listref of hashrefs, each containing
990 information about available z3950 servers. Each hashref has a format
991 like:
994 'checked' => 'checked',
995 'encoding' => 'MARC-8'
996 'icon' => undef,
997 'id' => 'LIBRARY OF CONGRESS',
998 'label' => '',
999 'name' => 'server',
1000 'opensearch' => '',
1001 'value' => 'z3950.loc.gov:7090/',
1002 'zed' => 1,
1006 =cut
1008 sub displayServers {
1009 my ( $position, $type ) = @_;
1010 my $dbh = C4::Context->dbh;
1012 my $strsth = 'SELECT * FROM z3950servers';
1013 my @where_clauses;
1014 my @bind_params;
1016 if ($position) {
1017 push @bind_params, $position;
1018 push @where_clauses, ' position = ? ';
1021 if ($type) {
1022 push @bind_params, $type;
1023 push @where_clauses, ' type = ? ';
1026 # reassemble where clause from where clause pieces
1027 if (@where_clauses) {
1028 $strsth .= ' WHERE ' . join( ' AND ', @where_clauses );
1031 my $rq = $dbh->prepare($strsth);
1032 $rq->execute(@bind_params);
1033 my @primaryserverloop;
1035 while ( my $data = $rq->fetchrow_hashref ) {
1036 push @primaryserverloop,
1037 { label => $data->{description},
1038 id => $data->{name},
1039 name => "server",
1040 value => $data->{host} . ":" . $data->{port} . "/" . $data->{database},
1041 encoding => ( $data->{encoding} ? $data->{encoding} : "iso-5426" ),
1042 checked => "checked",
1043 icon => $data->{icon},
1044 zed => $data->{type} eq 'zed',
1045 opensearch => $data->{type} eq 'opensearch'
1048 return \@primaryserverloop;
1051 =head2 GetAuthValCode
1053 $authvalcode = GetAuthValCode($kohafield,$frameworkcode);
1055 =cut
1057 sub GetAuthValCode {
1058 my ($kohafield,$fwcode) = @_;
1059 my $dbh = C4::Context->dbh;
1060 $fwcode='' unless $fwcode;
1061 my $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield=? and frameworkcode=?');
1062 $sth->execute($kohafield,$fwcode);
1063 my ($authvalcode) = $sth->fetchrow_array;
1064 return $authvalcode;
1067 =head2 GetAuthorisedValues
1069 $authvalues = GetAuthorisedValues([$category], [$selected]);
1071 This function returns all authorised values from the'authorised_value' table in a reference to array of hashrefs.
1073 C<$category> returns authorised values for just one category (optional).
1075 C<$opac> If set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1077 =cut
1079 sub GetAuthorisedValues {
1080 my ($category,$selected,$opac) = @_;
1081 my @results;
1082 my $dbh = C4::Context->dbh;
1083 my $query = "SELECT * FROM authorised_values";
1084 $query .= " WHERE category = '" . $category . "'" if $category;
1085 $query .= " ORDER BY category, lib, lib_opac";
1086 my $sth = $dbh->prepare($query);
1087 $sth->execute;
1088 while (my $data=$sth->fetchrow_hashref) {
1089 if ($selected eq $data->{'authorised_value'} ) {
1090 $data->{'selected'} = 1;
1092 if ($opac && $data->{'lib_opac'}) {
1093 $data->{'lib'} = $data->{'lib_opac'};
1095 push @results, $data;
1097 #my $data = $sth->fetchall_arrayref({});
1098 return \@results; #$data;
1101 =head2 GetAuthorisedValueCategories
1103 $auth_categories = GetAuthorisedValueCategories();
1105 Return an arrayref of all of the available authorised
1106 value categories.
1108 =cut
1110 sub GetAuthorisedValueCategories {
1111 my $dbh = C4::Context->dbh;
1112 my $sth = $dbh->prepare("SELECT DISTINCT category FROM authorised_values ORDER BY category");
1113 $sth->execute;
1114 my @results;
1115 while (my $category = $sth->fetchrow_array) {
1116 push @results, $category;
1118 return \@results;
1121 =head2 GetKohaAuthorisedValues
1123 Takes $kohafield, $fwcode as parameters.
1124 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1125 Returns hashref of Code => description
1126 Returns undef
1127 if no authorised value category is defined for the kohafield.
1129 =cut
1131 sub GetKohaAuthorisedValues {
1132 my ($kohafield,$fwcode,$opac) = @_;
1133 $fwcode='' unless $fwcode;
1134 my %values;
1135 my $dbh = C4::Context->dbh;
1136 my $avcode = GetAuthValCode($kohafield,$fwcode);
1137 if ($avcode) {
1138 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1139 $sth->execute($avcode);
1140 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1141 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1143 return \%values;
1144 } else {
1145 return undef;
1149 =head2 display_marc_indicators
1151 =over 4
1153 # field is a MARC::Field object
1154 my $display_form = C4::Koha::display_marc_indicators($field);
1156 =back
1158 Generate a display form of the indicators of a variable
1159 MARC field, replacing any blanks with '#'.
1161 =cut
1163 sub display_marc_indicators {
1164 my $field = shift;
1165 my $indicators = '';
1166 if ($field->tag() >= 10) {
1167 $indicators = $field->indicator(1) . $field->indicator(2);
1168 $indicators =~ s/ /#/g;
1170 return $indicators;
1173 sub GetNormalizedUPC {
1174 my ($record,$marcflavour) = @_;
1175 my (@fields,$upc);
1177 if ($marcflavour eq 'MARC21') {
1178 @fields = $record->field('024');
1179 foreach my $field (@fields) {
1180 my $indicator = $field->indicator(1);
1181 my $upc = _normalize_match_point($field->subfield('a'));
1182 if ($indicator == 1 and $upc ne '') {
1183 return $upc;
1187 else { # assume unimarc if not marc21
1188 @fields = $record->field('072');
1189 foreach my $field (@fields) {
1190 my $upc = _normalize_match_point($field->subfield('a'));
1191 if ($upc ne '') {
1192 return $upc;
1198 # Normalizes and returns the first valid ISBN found in the record
1199 sub GetNormalizedISBN {
1200 my ($isbn,$record,$marcflavour) = @_;
1201 my @fields;
1202 if ($isbn) {
1203 return _isbn_cleanup($isbn);
1205 return undef unless $record;
1207 if ($marcflavour eq 'MARC21') {
1208 @fields = $record->field('020');
1209 foreach my $field (@fields) {
1210 $isbn = $field->subfield('a');
1211 if ($isbn) {
1212 return _isbn_cleanup($isbn);
1213 } else {
1214 return undef;
1218 else { # assume unimarc if not marc21
1219 @fields = $record->field('010');
1220 foreach my $field (@fields) {
1221 my $isbn = $field->subfield('a');
1222 if ($isbn) {
1223 return _isbn_cleanup($isbn);
1224 } else {
1225 return undef;
1232 sub GetNormalizedEAN {
1233 my ($record,$marcflavour) = @_;
1234 my (@fields,$ean);
1236 if ($marcflavour eq 'MARC21') {
1237 @fields = $record->field('024');
1238 foreach my $field (@fields) {
1239 my $indicator = $field->indicator(1);
1240 $ean = _normalize_match_point($field->subfield('a'));
1241 if ($indicator == 3 and $ean ne '') {
1242 return $ean;
1246 else { # assume unimarc if not marc21
1247 @fields = $record->field('073');
1248 foreach my $field (@fields) {
1249 $ean = _normalize_match_point($field->subfield('a'));
1250 if ($ean ne '') {
1251 return $ean;
1256 sub GetNormalizedOCLCNumber {
1257 my ($record,$marcflavour) = @_;
1258 my (@fields,$oclc);
1260 if ($marcflavour eq 'MARC21') {
1261 @fields = $record->field('035');
1262 foreach my $field (@fields) {
1263 $oclc = $field->subfield('a');
1264 if ($oclc =~ /OCoLC/) {
1265 $oclc =~ s/\(OCoLC\)//;
1266 return $oclc;
1267 } else {
1268 return undef;
1272 else { # TODO: add UNIMARC fields
1276 sub _normalize_match_point {
1277 my $match_point = shift;
1278 (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
1279 $normalized_match_point =~ s/-//g;
1281 return $normalized_match_point;
1284 sub _isbn_cleanup ($) {
1285 my $normalized_isbn = shift;
1286 $normalized_isbn =~ s/-//g;
1287 $normalized_isbn =~/([0-9x]{1,})/i;
1288 $normalized_isbn = $1;
1289 if (
1290 $normalized_isbn =~ /\b(\d{13})\b/ or
1291 $normalized_isbn =~ /\b(\d{12})\b/i or
1292 $normalized_isbn =~ /\b(\d{10})\b/ or
1293 $normalized_isbn =~ /\b(\d{9}X)\b/i
1294 ) {
1295 return $1;
1297 return undef;
1302 __END__
1304 =head1 AUTHOR
1306 Koha Team
1308 =cut