Bug 5187: Show place of publication (MARC21, 260$c), XSLT
[koha.git] / C4 / Koha.pm
blobcb93034d5c99f39d7ff61a938ace91a5d1659e54
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
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 use strict;
22 #use warnings; FIXME - Bug 2505
23 use C4::Context;
24 use C4::Output;
25 use URI::Split qw(uri_split);
26 use Memoize;
28 use vars qw($VERSION @ISA @EXPORT $DEBUG);
30 BEGIN {
31 $VERSION = 3.01;
32 require Exporter;
33 @ISA = qw(Exporter);
34 @EXPORT = qw(
35 &slashifyDate
36 &DisplayISBN
37 &subfield_is_koha_internal_p
38 &GetPrinters &GetPrinter
39 &GetItemTypes &getitemtypeinfo
40 &GetCcodes
41 &GetSupportName &GetSupportList
42 &get_itemtypeinfos_of
43 &getframeworks &getframeworkinfo
44 &getauthtypes &getauthtype
45 &getallthemes
46 &getFacets
47 &displayServers
48 &getnbpages
49 &get_infos_of
50 &get_notforloan_label_of
51 &getitemtypeimagedir
52 &getitemtypeimagesrc
53 &getitemtypeimagelocation
54 &GetAuthorisedValues
55 &GetAuthorisedValueCategories
56 &GetKohaAuthorisedValues
57 &GetKohaAuthorisedValuesFromField
58 &GetAuthValCode
59 &GetNormalizedUPC
60 &GetNormalizedISBN
61 &GetNormalizedEAN
62 &GetNormalizedOCLCNumber
64 $DEBUG
66 $DEBUG = 0;
69 # expensive functions
70 memoize('GetAuthorisedValues');
72 =head1 NAME
74 C4::Koha - Perl Module containing convenience functions for Koha scripts
76 =head1 SYNOPSIS
78 use C4::Koha;
80 =head1 DESCRIPTION
82 Koha.pm provides many functions for Koha scripts.
84 =head1 FUNCTIONS
86 =cut
88 =head2 slashifyDate
90 $slash_date = &slashifyDate($dash_date);
92 Takes a string of the form "DD-MM-YYYY" (or anything separated by
93 dashes), converts it to the form "YYYY/MM/DD", and returns the result.
95 =cut
97 sub slashifyDate {
99 # accepts a date of the form xx-xx-xx[xx] and returns it in the
100 # form xx/xx/xx[xx]
101 my @dateOut = split( '-', shift );
102 return ("$dateOut[2]/$dateOut[1]/$dateOut[0]");
106 =head2 DisplayISBN
108 my $string = DisplayISBN( $isbn );
110 =cut
112 sub DisplayISBN {
113 my ($isbn) = @_;
114 if (length ($isbn)<13){
115 my $seg1;
116 if ( substr( $isbn, 0, 1 ) <= 7 ) {
117 $seg1 = substr( $isbn, 0, 1 );
119 elsif ( substr( $isbn, 0, 2 ) <= 94 ) {
120 $seg1 = substr( $isbn, 0, 2 );
122 elsif ( substr( $isbn, 0, 3 ) <= 995 ) {
123 $seg1 = substr( $isbn, 0, 3 );
125 elsif ( substr( $isbn, 0, 4 ) <= 9989 ) {
126 $seg1 = substr( $isbn, 0, 4 );
128 else {
129 $seg1 = substr( $isbn, 0, 5 );
131 my $x = substr( $isbn, length($seg1) );
132 my $seg2;
133 if ( substr( $x, 0, 2 ) <= 19 ) {
135 # if(sTmp2 < 10) sTmp2 = "0" sTmp2;
136 $seg2 = substr( $x, 0, 2 );
138 elsif ( substr( $x, 0, 3 ) <= 699 ) {
139 $seg2 = substr( $x, 0, 3 );
141 elsif ( substr( $x, 0, 4 ) <= 8399 ) {
142 $seg2 = substr( $x, 0, 4 );
144 elsif ( substr( $x, 0, 5 ) <= 89999 ) {
145 $seg2 = substr( $x, 0, 5 );
147 elsif ( substr( $x, 0, 6 ) <= 9499999 ) {
148 $seg2 = substr( $x, 0, 6 );
150 else {
151 $seg2 = substr( $x, 0, 7 );
153 my $seg3 = substr( $x, length($seg2) );
154 $seg3 = substr( $seg3, 0, length($seg3) - 1 );
155 my $seg4 = substr( $x, -1, 1 );
156 return "$seg1-$seg2-$seg3-$seg4";
157 } else {
158 my $seg1;
159 $seg1 = substr( $isbn, 0, 3 );
160 my $seg2;
161 if ( substr( $isbn, 3, 1 ) <= 7 ) {
162 $seg2 = substr( $isbn, 3, 1 );
164 elsif ( substr( $isbn, 3, 2 ) <= 94 ) {
165 $seg2 = substr( $isbn, 3, 2 );
167 elsif ( substr( $isbn, 3, 3 ) <= 995 ) {
168 $seg2 = substr( $isbn, 3, 3 );
170 elsif ( substr( $isbn, 3, 4 ) <= 9989 ) {
171 $seg2 = substr( $isbn, 3, 4 );
173 else {
174 $seg2 = substr( $isbn, 3, 5 );
176 my $x = substr( $isbn, length($seg2) +3);
177 my $seg3;
178 if ( substr( $x, 0, 2 ) <= 19 ) {
180 # if(sTmp2 < 10) sTmp2 = "0" sTmp2;
181 $seg3 = substr( $x, 0, 2 );
183 elsif ( substr( $x, 0, 3 ) <= 699 ) {
184 $seg3 = substr( $x, 0, 3 );
186 elsif ( substr( $x, 0, 4 ) <= 8399 ) {
187 $seg3 = substr( $x, 0, 4 );
189 elsif ( substr( $x, 0, 5 ) <= 89999 ) {
190 $seg3 = substr( $x, 0, 5 );
192 elsif ( substr( $x, 0, 6 ) <= 9499999 ) {
193 $seg3 = substr( $x, 0, 6 );
195 else {
196 $seg3 = substr( $x, 0, 7 );
198 my $seg4 = substr( $x, length($seg3) );
199 $seg4 = substr( $seg4, 0, length($seg4) - 1 );
200 my $seg5 = substr( $x, -1, 1 );
201 return "$seg1-$seg2-$seg3-$seg4-$seg5";
205 # FIXME.. this should be moved to a MARC-specific module
206 sub subfield_is_koha_internal_p ($) {
207 my ($subfield) = @_;
209 # We could match on 'lib' and 'tab' (and 'mandatory', & more to come!)
210 # But real MARC subfields are always single-character
211 # so it really is safer just to check the length
213 return length $subfield != 1;
216 =head2 GetSupportName
218 $itemtypename = &GetSupportName($codestring);
220 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>
484 =cut
486 sub getframeworks {
488 # returns a reference to a hash of references to branches...
489 my %itemtypes;
490 my $dbh = C4::Context->dbh;
491 my $sth = $dbh->prepare("select * from biblio_framework");
492 $sth->execute;
493 while ( my $IT = $sth->fetchrow_hashref ) {
494 $itemtypes{ $IT->{'frameworkcode'} } = $IT;
496 return ( \%itemtypes );
499 =head2 getframeworkinfo
501 $frameworkinfo = &getframeworkinfo($frameworkcode);
503 Returns information about an frameworkcode.
505 =cut
507 sub getframeworkinfo {
508 my ($frameworkcode) = @_;
509 my $dbh = C4::Context->dbh;
510 my $sth =
511 $dbh->prepare("select * from biblio_framework where frameworkcode=?");
512 $sth->execute($frameworkcode);
513 my $res = $sth->fetchrow_hashref;
514 return $res;
517 =head2 getitemtypeinfo
519 $itemtype = &getitemtype($itemtype);
521 Returns information about an itemtype.
523 =cut
525 sub getitemtypeinfo {
526 my ($itemtype) = @_;
527 my $dbh = C4::Context->dbh;
528 my $sth = $dbh->prepare("select * from itemtypes where itemtype=?");
529 $sth->execute($itemtype);
530 my $res = $sth->fetchrow_hashref;
532 $res->{imageurl} = getitemtypeimagelocation( 'intranet', $res->{imageurl} );
534 return $res;
537 =head2 getitemtypeimagedir
539 my $directory = getitemtypeimagedir( 'opac' );
541 pass in 'opac' or 'intranet'. Defaults to 'opac'.
543 returns the full path to the appropriate directory containing images.
545 =cut
547 sub getitemtypeimagedir {
548 my $src = shift || 'opac';
549 if ($src eq 'intranet') {
550 return C4::Context->config('intrahtdocs') . '/' .C4::Context->preference('template') . '/img/itemtypeimg';
551 } else {
552 return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('template') . '/itemtypeimg';
556 sub getitemtypeimagesrc {
557 my $src = shift || 'opac';
558 if ($src eq 'intranet') {
559 return '/intranet-tmpl' . '/' . C4::Context->preference('template') . '/img/itemtypeimg';
560 } else {
561 return '/opac-tmpl' . '/' . C4::Context->preference('template') . '/itemtypeimg';
565 sub getitemtypeimagelocation($$) {
566 my ( $src, $image ) = @_;
568 return '' if ( !$image );
570 my $scheme = ( uri_split( $image ) )[0];
572 return $image if ( $scheme );
574 return getitemtypeimagesrc( $src ) . '/' . $image;
577 =head3 _getImagesFromDirectory
579 Find all of the image files in a directory in the filesystem
581 parameters: a directory name
583 returns: a list of images in that directory.
585 Notes: this does not traverse into subdirectories. See
586 _getSubdirectoryNames for help with that.
587 Images are assumed to be files with .gif or .png file extensions.
588 The image names returned do not have the directory name on them.
590 =cut
592 sub _getImagesFromDirectory {
593 my $directoryname = shift;
594 return unless defined $directoryname;
595 return unless -d $directoryname;
597 if ( opendir ( my $dh, $directoryname ) ) {
598 my @images = grep { /\.(gif|png)$/i } readdir( $dh );
599 closedir $dh;
600 return @images;
601 } else {
602 warn "unable to opendir $directoryname: $!";
603 return;
607 =head3 _getSubdirectoryNames
609 Find all of the directories in a directory in the filesystem
611 parameters: a directory name
613 returns: a list of subdirectories in that directory.
615 Notes: this does not traverse into subdirectories. Only the first
616 level of subdirectories are returned.
617 The directory names returned don't have the parent directory name on them.
619 =cut
621 sub _getSubdirectoryNames {
622 my $directoryname = shift;
623 return unless defined $directoryname;
624 return unless -d $directoryname;
626 if ( opendir ( my $dh, $directoryname ) ) {
627 my @directories = grep { -d File::Spec->catfile( $directoryname, $_ ) && ! ( /^\./ ) } readdir( $dh );
628 closedir $dh;
629 return @directories;
630 } else {
631 warn "unable to opendir $directoryname: $!";
632 return;
636 =head3 getImageSets
638 returns: a listref of hashrefs. Each hash represents another collection of images.
640 { imagesetname => 'npl', # the name of the image set (npl is the original one)
641 images => listref of image hashrefs
644 each image is represented by a hashref like this:
646 { KohaImage => 'npl/image.gif',
647 StaffImageUrl => '/intranet-tmpl/prog/img/itemtypeimg/npl/image.gif',
648 OpacImageURL => '/opac-tmpl/prog/itemtypeimg/npl/image.gif'
649 checked => 0 or 1: was this the image passed to this method?
650 Note: I'd like to remove this somehow.
653 =cut
655 sub getImageSets {
656 my %params = @_;
657 my $checked = $params{'checked'} || '';
659 my $paths = { staff => { filesystem => getitemtypeimagedir('intranet'),
660 url => getitemtypeimagesrc('intranet'),
662 opac => { filesystem => getitemtypeimagedir('opac'),
663 url => getitemtypeimagesrc('opac'),
667 my @imagesets = (); # list of hasrefs of image set data to pass to template
668 my @subdirectories = _getSubdirectoryNames( $paths->{'staff'}{'filesystem'} );
670 foreach my $imagesubdir ( @subdirectories ) {
671 my @imagelist = (); # hashrefs of image info
672 my @imagenames = _getImagesFromDirectory( File::Spec->catfile( $paths->{'staff'}{'filesystem'}, $imagesubdir ) );
673 foreach my $thisimage ( @imagenames ) {
674 push( @imagelist,
675 { KohaImage => "$imagesubdir/$thisimage",
676 StaffImageUrl => join( '/', $paths->{'staff'}{'url'}, $imagesubdir, $thisimage ),
677 OpacImageUrl => join( '/', $paths->{'opac'}{'url'}, $imagesubdir, $thisimage ),
678 checked => "$imagesubdir/$thisimage" eq $checked ? 1 : 0,
682 push @imagesets, { imagesetname => $imagesubdir,
683 images => \@imagelist };
686 return \@imagesets;
689 =head2 GetPrinters
691 $printers = &GetPrinters();
692 @queues = keys %$printers;
694 Returns information about existing printer queues.
696 C<$printers> is a reference-to-hash whose keys are the print queues
697 defined in the printers table of the Koha database. The values are
698 references-to-hash, whose keys are the fields in the printers table.
700 =cut
702 sub GetPrinters {
703 my %printers;
704 my $dbh = C4::Context->dbh;
705 my $sth = $dbh->prepare("select * from printers");
706 $sth->execute;
707 while ( my $printer = $sth->fetchrow_hashref ) {
708 $printers{ $printer->{'printqueue'} } = $printer;
710 return ( \%printers );
713 =head2 GetPrinter
715 $printer = GetPrinter( $query, $printers );
717 =cut
719 sub GetPrinter ($$) {
720 my ( $query, $printers ) = @_; # get printer for this query from printers
721 my $printer = $query->param('printer');
722 my %cookie = $query->cookie('userenv');
723 ($printer) || ( $printer = $cookie{'printer'} ) || ( $printer = '' );
724 ( $printers->{$printer} ) || ( $printer = ( keys %$printers )[0] );
725 return $printer;
728 =head2 getnbpages
730 Returns the number of pages to display in a pagination bar, given the number
731 of items and the number of items per page.
733 =cut
735 sub getnbpages {
736 my ( $nb_items, $nb_items_per_page ) = @_;
738 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
741 =head2 getallthemes
743 (@themes) = &getallthemes('opac');
744 (@themes) = &getallthemes('intranet');
746 Returns an array of all available themes.
748 =cut
750 sub getallthemes {
751 my $type = shift;
752 my $htdocs;
753 my @themes;
754 if ( $type eq 'intranet' ) {
755 $htdocs = C4::Context->config('intrahtdocs');
757 else {
758 $htdocs = C4::Context->config('opachtdocs');
760 opendir D, "$htdocs";
761 my @dirlist = readdir D;
762 foreach my $directory (@dirlist) {
763 -d "$htdocs/$directory/en" and push @themes, $directory;
765 return @themes;
768 sub getFacets {
769 my $facets;
770 if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
771 $facets = [
773 link_value => 'su-to',
774 label_value => 'Topics',
775 tags =>
776 [ '600', '601', '602', '603', '604', '605', '606', '610' ],
777 subfield => 'a',
780 link_value => 'su-geo',
781 label_value => 'Places',
782 tags => ['651'],
783 subfield => 'a',
786 link_value => 'su-ut',
787 label_value => 'Titles',
788 tags => [ '500', '501', '502', '503', '504', ],
789 subfield => 'a',
792 link_value => 'au',
793 label_value => 'Authors',
794 tags => [ '700', '701', '702', ],
795 subfield => 'a',
798 link_value => 'se',
799 label_value => 'Series',
800 tags => ['225'],
801 subfield => 'a',
805 my $library_facet;
807 $library_facet = {
808 link_value => 'branch',
809 label_value => 'Libraries',
810 tags => [ '995', ],
811 subfield => 'b',
812 expanded => '1',
814 push @$facets, $library_facet unless C4::Context->preference("singleBranchMode");
816 else {
817 $facets = [
819 link_value => 'su-to',
820 label_value => 'Topics',
821 tags => ['650'],
822 subfield => 'a',
826 # link_value => 'su-na',
827 # label_value => 'People and Organizations',
828 # tags => ['600', '610', '611'],
829 # subfield => 'a',
830 # },
832 link_value => 'su-geo',
833 label_value => 'Places',
834 tags => ['651'],
835 subfield => 'a',
838 link_value => 'su-ut',
839 label_value => 'Titles',
840 tags => ['630'],
841 subfield => 'a',
844 link_value => 'au',
845 label_value => 'Authors',
846 tags => [ '100', '110', '700', ],
847 subfield => 'a',
850 link_value => 'se',
851 label_value => 'Series',
852 tags => [ '440', '490', ],
853 subfield => 'a',
856 my $library_facet;
857 $library_facet = {
858 link_value => 'branch',
859 label_value => 'Libraries',
860 tags => [ '952', ],
861 subfield => 'b',
862 expanded => '1',
864 push @$facets, $library_facet unless C4::Context->preference("singleBranchMode");
866 return $facets;
869 =head2 get_infos_of
871 Return a href where a key is associated to a href. You give a query,
872 the name of the key among the fields returned by the query. If you
873 also give as third argument the name of the value, the function
874 returns a href of scalar. The optional 4th argument is an arrayref of
875 items passed to the C<execute()> call. It is designed to bind
876 parameters to any placeholders in your SQL.
878 my $query = '
879 SELECT itemnumber,
880 notforloan,
881 barcode
882 FROM items
885 # generic href of any information on the item, href of href.
886 my $iteminfos_of = get_infos_of($query, 'itemnumber');
887 print $iteminfos_of->{$itemnumber}{barcode};
889 # specific information, href of scalar
890 my $barcode_of_item = get_infos_of($query, 'itemnumber', 'barcode');
891 print $barcode_of_item->{$itemnumber};
893 =cut
895 sub get_infos_of {
896 my ( $query, $key_name, $value_name, $bind_params ) = @_;
898 my $dbh = C4::Context->dbh;
900 my $sth = $dbh->prepare($query);
901 $sth->execute( @$bind_params );
903 my %infos_of;
904 while ( my $row = $sth->fetchrow_hashref ) {
905 if ( defined $value_name ) {
906 $infos_of{ $row->{$key_name} } = $row->{$value_name};
908 else {
909 $infos_of{ $row->{$key_name} } = $row;
912 $sth->finish;
914 return \%infos_of;
917 =head2 get_notforloan_label_of
919 my $notforloan_label_of = get_notforloan_label_of();
921 Each authorised value of notforloan (information available in items and
922 itemtypes) is link to a single label.
924 Returns a href where keys are authorised values and values are corresponding
925 labels.
927 foreach my $authorised_value (keys %{$notforloan_label_of}) {
928 printf(
929 "authorised_value: %s => %s\n",
930 $authorised_value,
931 $notforloan_label_of->{$authorised_value}
935 =cut
937 # FIXME - why not use GetAuthorisedValues ??
939 sub get_notforloan_label_of {
940 my $dbh = C4::Context->dbh;
942 my $query = '
943 SELECT authorised_value
944 FROM marc_subfield_structure
945 WHERE kohafield = \'items.notforloan\'
946 LIMIT 0, 1
948 my $sth = $dbh->prepare($query);
949 $sth->execute();
950 my ($statuscode) = $sth->fetchrow_array();
952 $query = '
953 SELECT lib,
954 authorised_value
955 FROM authorised_values
956 WHERE category = ?
958 $sth = $dbh->prepare($query);
959 $sth->execute($statuscode);
960 my %notforloan_label_of;
961 while ( my $row = $sth->fetchrow_hashref ) {
962 $notforloan_label_of{ $row->{authorised_value} } = $row->{lib};
964 $sth->finish;
966 return \%notforloan_label_of;
969 =head2 displayServers
971 my $servers = displayServers();
972 my $servers = displayServers( $position );
973 my $servers = displayServers( $position, $type );
975 displayServers returns a listref of hashrefs, each containing
976 information about available z3950 servers. Each hashref has a format
977 like:
980 'checked' => 'checked',
981 'encoding' => 'MARC-8'
982 'icon' => undef,
983 'id' => 'LIBRARY OF CONGRESS',
984 'label' => '',
985 'name' => 'server',
986 'opensearch' => '',
987 'value' => 'z3950.loc.gov:7090/',
988 'zed' => 1,
991 =cut
993 sub displayServers {
994 my ( $position, $type ) = @_;
995 my $dbh = C4::Context->dbh;
997 my $strsth = 'SELECT * FROM z3950servers';
998 my @where_clauses;
999 my @bind_params;
1001 if ($position) {
1002 push @bind_params, $position;
1003 push @where_clauses, ' position = ? ';
1006 if ($type) {
1007 push @bind_params, $type;
1008 push @where_clauses, ' type = ? ';
1011 # reassemble where clause from where clause pieces
1012 if (@where_clauses) {
1013 $strsth .= ' WHERE ' . join( ' AND ', @where_clauses );
1016 my $rq = $dbh->prepare($strsth);
1017 $rq->execute(@bind_params);
1018 my @primaryserverloop;
1020 while ( my $data = $rq->fetchrow_hashref ) {
1021 push @primaryserverloop,
1022 { label => $data->{description},
1023 id => $data->{name},
1024 name => "server",
1025 value => $data->{host} . ":" . $data->{port} . "/" . $data->{database},
1026 encoding => ( $data->{encoding} ? $data->{encoding} : "iso-5426" ),
1027 checked => "checked",
1028 icon => $data->{icon},
1029 zed => $data->{type} eq 'zed',
1030 opensearch => $data->{type} eq 'opensearch'
1033 return \@primaryserverloop;
1036 =head2 GetAuthValCode
1038 $authvalcode = GetAuthValCode($kohafield,$frameworkcode);
1040 =cut
1042 sub GetAuthValCode {
1043 my ($kohafield,$fwcode) = @_;
1044 my $dbh = C4::Context->dbh;
1045 $fwcode='' unless $fwcode;
1046 my $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield=? and frameworkcode=?');
1047 $sth->execute($kohafield,$fwcode);
1048 my ($authvalcode) = $sth->fetchrow_array;
1049 return $authvalcode;
1052 =head2 GetAuthValCodeFromField
1054 $authvalcode = GetAuthValCodeFromField($field,$subfield,$frameworkcode);
1056 C<$subfield> can be undefined
1058 =cut
1060 sub GetAuthValCodeFromField {
1061 my ($field,$subfield,$fwcode) = @_;
1062 my $dbh = C4::Context->dbh;
1063 $fwcode='' unless $fwcode;
1064 my $sth;
1065 if (defined $subfield) {
1066 $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?');
1067 $sth->execute($field,$subfield,$fwcode);
1068 } else {
1069 $sth = $dbh->prepare('select authorised_value from marc_tag_structure where tagfield=? and frameworkcode=?');
1070 $sth->execute($field,$fwcode);
1072 my ($authvalcode) = $sth->fetchrow_array;
1073 return $authvalcode;
1076 =head2 GetAuthorisedValues
1078 $authvalues = GetAuthorisedValues([$category], [$selected]);
1080 This function returns all authorised values from the'authorised_value' table in a reference to array of hashrefs.
1082 C<$category> returns authorised values for just one category (optional).
1084 C<$opac> If set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1086 =cut
1088 sub GetAuthorisedValues {
1089 my ($category,$selected,$opac) = @_;
1090 my @results;
1091 my $dbh = C4::Context->dbh;
1092 my $query = "SELECT * FROM authorised_values";
1093 $query .= " WHERE category = '" . $category . "'" if $category;
1094 $query .= " ORDER BY category, lib, lib_opac";
1095 my $sth = $dbh->prepare($query);
1096 $sth->execute;
1097 while (my $data=$sth->fetchrow_hashref) {
1098 if ($selected && $selected eq $data->{'authorised_value'} ) {
1099 $data->{'selected'} = 1;
1101 if ($opac && $data->{'lib_opac'}) {
1102 $data->{'lib'} = $data->{'lib_opac'};
1104 push @results, $data;
1106 #my $data = $sth->fetchall_arrayref({});
1107 return \@results; #$data;
1110 =head2 GetAuthorisedValueCategories
1112 $auth_categories = GetAuthorisedValueCategories();
1114 Return an arrayref of all of the available authorised
1115 value categories.
1117 =cut
1119 sub GetAuthorisedValueCategories {
1120 my $dbh = C4::Context->dbh;
1121 my $sth = $dbh->prepare("SELECT DISTINCT category FROM authorised_values ORDER BY category");
1122 $sth->execute;
1123 my @results;
1124 while (my $category = $sth->fetchrow_array) {
1125 push @results, $category;
1127 return \@results;
1130 =head2 GetKohaAuthorisedValues
1132 Takes $kohafield, $fwcode as parameters.
1134 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1136 Returns hashref of Code => description
1138 Returns undef if no authorised value category is defined for the kohafield.
1140 =cut
1142 sub GetKohaAuthorisedValues {
1143 my ($kohafield,$fwcode,$opac) = @_;
1144 $fwcode='' unless $fwcode;
1145 my %values;
1146 my $dbh = C4::Context->dbh;
1147 my $avcode = GetAuthValCode($kohafield,$fwcode);
1148 if ($avcode) {
1149 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1150 $sth->execute($avcode);
1151 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1152 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1154 return \%values;
1155 } else {
1156 return undef;
1160 =head2 GetKohaAuthorisedValuesFromField
1162 Takes $field, $subfield, $fwcode as parameters.
1164 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1165 $subfield can be undefined
1167 Returns hashref of Code => description
1169 Returns undef if no authorised value category is defined for the given field and subfield
1171 =cut
1173 sub GetKohaAuthorisedValuesFromField {
1174 my ($field, $subfield, $fwcode,$opac) = @_;
1175 $fwcode='' unless $fwcode;
1176 my %values;
1177 my $dbh = C4::Context->dbh;
1178 my $avcode = GetAuthValCodeFromField($field, $subfield, $fwcode);
1179 if ($avcode) {
1180 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1181 $sth->execute($avcode);
1182 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1183 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1185 return \%values;
1186 } else {
1187 return undef;
1191 =head2 display_marc_indicators
1193 my $display_form = C4::Koha::display_marc_indicators($field);
1195 C<$field> is a MARC::Field object
1197 Generate a display form of the indicators of a variable
1198 MARC field, replacing any blanks with '#'.
1200 =cut
1202 sub display_marc_indicators {
1203 my $field = shift;
1204 my $indicators = '';
1205 if ($field->tag() >= 10) {
1206 $indicators = $field->indicator(1) . $field->indicator(2);
1207 $indicators =~ s/ /#/g;
1209 return $indicators;
1212 sub GetNormalizedUPC {
1213 my ($record,$marcflavour) = @_;
1214 my (@fields,$upc);
1216 if ($marcflavour eq 'MARC21') {
1217 @fields = $record->field('024');
1218 foreach my $field (@fields) {
1219 my $indicator = $field->indicator(1);
1220 my $upc = _normalize_match_point($field->subfield('a'));
1221 if ($indicator == 1 and $upc ne '') {
1222 return $upc;
1226 else { # assume unimarc if not marc21
1227 @fields = $record->field('072');
1228 foreach my $field (@fields) {
1229 my $upc = _normalize_match_point($field->subfield('a'));
1230 if ($upc ne '') {
1231 return $upc;
1237 # Normalizes and returns the first valid ISBN found in the record
1238 sub GetNormalizedISBN {
1239 my ($isbn,$record,$marcflavour) = @_;
1240 my @fields;
1241 if ($isbn) {
1242 return _isbn_cleanup($isbn);
1244 return undef unless $record;
1246 if ($marcflavour eq 'MARC21') {
1247 @fields = $record->field('020');
1248 foreach my $field (@fields) {
1249 $isbn = $field->subfield('a');
1250 if ($isbn) {
1251 return _isbn_cleanup($isbn);
1252 } else {
1253 return undef;
1257 else { # assume unimarc if not marc21
1258 @fields = $record->field('010');
1259 foreach my $field (@fields) {
1260 my $isbn = $field->subfield('a');
1261 if ($isbn) {
1262 return _isbn_cleanup($isbn);
1263 } else {
1264 return undef;
1271 sub GetNormalizedEAN {
1272 my ($record,$marcflavour) = @_;
1273 my (@fields,$ean);
1275 if ($marcflavour eq 'MARC21') {
1276 @fields = $record->field('024');
1277 foreach my $field (@fields) {
1278 my $indicator = $field->indicator(1);
1279 $ean = _normalize_match_point($field->subfield('a'));
1280 if ($indicator == 3 and $ean ne '') {
1281 return $ean;
1285 else { # assume unimarc if not marc21
1286 @fields = $record->field('073');
1287 foreach my $field (@fields) {
1288 $ean = _normalize_match_point($field->subfield('a'));
1289 if ($ean ne '') {
1290 return $ean;
1295 sub GetNormalizedOCLCNumber {
1296 my ($record,$marcflavour) = @_;
1297 my (@fields,$oclc);
1299 if ($marcflavour eq 'MARC21') {
1300 @fields = $record->field('035');
1301 foreach my $field (@fields) {
1302 $oclc = $field->subfield('a');
1303 if ($oclc =~ /OCoLC/) {
1304 $oclc =~ s/\(OCoLC\)//;
1305 return $oclc;
1306 } else {
1307 return undef;
1311 else { # TODO: add UNIMARC fields
1315 sub _normalize_match_point {
1316 my $match_point = shift;
1317 (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
1318 $normalized_match_point =~ s/-//g;
1320 return $normalized_match_point;
1323 sub _isbn_cleanup ($) {
1324 my $normalized_isbn = shift;
1325 $normalized_isbn =~ s/-//g;
1326 $normalized_isbn =~/([0-9x]{1,})/i;
1327 $normalized_isbn = $1;
1328 if (
1329 $normalized_isbn =~ /\b(\d{13})\b/ or
1330 $normalized_isbn =~ /\b(\d{12})\b/i or
1331 $normalized_isbn =~ /\b(\d{10})\b/ or
1332 $normalized_isbn =~ /\b(\d{9}X)\b/i
1333 ) {
1334 return $1;
1336 return undef;
1341 __END__
1343 =head1 AUTHOR
1345 Koha Team
1347 =cut