3 # Copyright 2000-2002 Katipo Communications
4 # Parts Copyright 2010 Nelsonville Public Library
5 # Parts copyright 2010 BibLibre
7 # This file is part of Koha.
9 # Koha is free software; you can redistribute it and/or modify it
10 # under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
14 # Koha is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with Koha; if not, see <http://www.gnu.org/licenses>.
24 #use warnings; FIXME - Bug 2505
28 use Koha::DateUtils qw(dt_from_string);
30 use Koha::MarcSubfieldStructures;
31 use DateTime::Format::MySQL;
33 use autouse 'Data::cselectall_arrayref' => qw(Dumper);
34 use DBI qw(:sql_types);
35 use vars qw(@ISA @EXPORT @EXPORT_OK $DEBUG);
41 &GetPrinters &GetPrinter
42 &GetItemTypes &getitemtypeinfo
43 &GetItemTypesCategorized &GetItemTypesByCategory
44 &getframeworks &getframeworkinfo
50 &get_notforloan_label_of
53 &getitemtypeimagelocation
55 &GetAuthorisedValueCategories
56 &GetKohaAuthorisedValues
57 &GetKohaAuthorisedValuesMapping
58 &GetAuthorisedValueByCode
63 &GetNormalizedOCLCNumber
73 @EXPORT_OK = qw( GetDailyQuote );
78 C4::Koha - Perl Module containing convenience functions for Koha scripts
86 Koha.pm provides many functions for Koha scripts.
94 $itemtypes = &GetItemTypes( style => $style );
96 Returns information about existing itemtypes.
99 style: either 'array' or 'hash', defaults to 'hash'.
100 'array' returns an arrayref,
101 'hash' return a hashref with the itemtype value as the key
103 build a HTML select with the following code :
105 =head3 in PERL SCRIPT
107 my $itemtypes = GetItemTypes;
109 foreach my $thisitemtype (sort keys %$itemtypes) {
110 my $selected = 1 if $thisitemtype eq $itemtype;
111 my %row =(value => $thisitemtype,
112 selected => $selected,
113 description => $itemtypes->{$thisitemtype}->{'description'},
115 push @itemtypesloop, \%row;
117 $template->param(itemtypeloop => \@itemtypesloop);
121 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
122 <select name="itemtype">
123 <option value="">Default</option>
124 <!-- TMPL_LOOP name="itemtypeloop" -->
125 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="description" --></option>
128 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
129 <input type="submit" value="OK" class="button">
136 my $style = defined( $params{'style'} ) ? $params{'style'} : 'hash';
138 require C4::Languages;
139 my $language = C4::Languages::getlanguage();
140 # returns a reference to a hash of references to itemtypes...
141 my $dbh = C4::Context->dbh;
145 itemtypes.description,
146 itemtypes.rentalcharge,
147 itemtypes.notforloan,
150 itemtypes.checkinmsg,
151 itemtypes.checkinmsgtype,
152 itemtypes.sip_media_type,
153 itemtypes.hideinopac,
154 itemtypes.searchcategory,
155 COALESCE( localization.translation, itemtypes.description ) AS translated_description
157 LEFT JOIN localization ON itemtypes.itemtype = localization.code
158 AND localization.entity = 'itemtypes'
159 AND localization.lang = ?
162 my $sth = $dbh->prepare($query);
163 $sth->execute( $language );
165 if ( $style eq 'hash' ) {
167 while ( my $IT = $sth->fetchrow_hashref ) {
168 $itemtypes{ $IT->{'itemtype'} } = $IT;
170 return ( \%itemtypes );
172 return [ sort { lc $a->{translated_description} cmp lc $b->{translated_description} } @{ $sth->fetchall_arrayref( {} ) } ];
176 =head2 GetItemTypesCategorized
178 $categories = GetItemTypesCategorized();
180 Returns a hashref containing search categories.
181 A search category will be put in the hash if at least one of its itemtypes is visible in OPAC.
182 The categories must be part of Authorized Values (ITEMTYPECAT)
186 sub GetItemTypesCategorized {
187 my $dbh = C4::Context->dbh;
188 # Order is important, so that partially hidden (some items are not visible in OPAC) search
189 # categories will be visible. hideinopac=0 must be last.
191 SELECT itemtype, description, imageurl, hideinopac, 0 as 'iscat' FROM itemtypes WHERE ISNULL(searchcategory) or length(searchcategory) = 0
193 SELECT DISTINCT searchcategory AS `itemtype`,
194 authorised_values.lib_opac AS description,
195 authorised_values.imageurl AS imageurl,
196 hideinopac, 1 as 'iscat'
198 LEFT JOIN authorised_values ON searchcategory = authorised_value
199 WHERE searchcategory > '' and hideinopac=1
201 SELECT DISTINCT searchcategory AS `itemtype`,
202 authorised_values.lib_opac AS description,
203 authorised_values.imageurl AS imageurl,
204 hideinopac, 1 as 'iscat'
206 LEFT JOIN authorised_values ON searchcategory = authorised_value
207 WHERE searchcategory > '' and hideinopac=0
209 return ($dbh->selectall_hashref($query,'itemtype'));
212 =head2 GetItemTypesByCategory
214 @results = GetItemTypesByCategory( $searchcategory );
216 Returns the itemtype code of all itemtypes included in a searchcategory.
220 sub GetItemTypesByCategory {
224 my $dbh = C4::Context->dbh;
225 my $query = qq|SELECT itemtype FROM itemtypes WHERE searchcategory=?|;
226 my $tmp=$dbh->selectcol_arrayref($query,undef,$category);
232 $frameworks = &getframework();
234 Returns information about existing frameworks
236 build a HTML select with the following code :
238 =head3 in PERL SCRIPT
240 my $frameworks = getframeworks();
242 foreach my $thisframework (keys %$frameworks) {
243 my $selected = 1 if $thisframework eq $frameworkcode;
245 value => $thisframework,
246 selected => $selected,
247 description => $frameworks->{$thisframework}->{'frameworktext'},
249 push @frameworksloop, \%row;
251 $template->param(frameworkloop => \@frameworksloop);
255 <form action="[% script_name %] method=post>
256 <select name="frameworkcode">
257 <option value="">Default</option>
258 [% FOREACH framework IN frameworkloop %]
259 [% IF ( framework.selected ) %]
260 <option value="[% framework.value %]" selected="selected">[% framework.description %]</option>
262 <option value="[% framework.value %]">[% framework.description %]</option>
266 <input type=text name=searchfield value="[% searchfield %]">
267 <input type="submit" value="OK" class="button">
274 # returns a reference to a hash of references to branches...
276 my $dbh = C4::Context->dbh;
277 my $sth = $dbh->prepare("select * from biblio_framework");
279 while ( my $IT = $sth->fetchrow_hashref ) {
280 $itemtypes{ $IT->{'frameworkcode'} } = $IT;
282 return ( \%itemtypes );
285 =head2 GetFrameworksLoop
287 $frameworks = GetFrameworksLoop( $frameworkcode );
289 Returns the loop suggested on getframework(), but ordered by framework description.
291 build a HTML select with the following code :
293 =head3 in PERL SCRIPT
295 $template->param( frameworkloop => GetFrameworksLoop( $frameworkcode ) );
299 Same as getframework()
301 <form action="[% script_name %] method=post>
302 <select name="frameworkcode">
303 <option value="">Default</option>
304 [% FOREACH framework IN frameworkloop %]
305 [% IF ( framework.selected ) %]
306 <option value="[% framework.value %]" selected="selected">[% framework.description %]</option>
308 <option value="[% framework.value %]">[% framework.description %]</option>
312 <input type=text name=searchfield value="[% searchfield %]">
313 <input type="submit" value="OK" class="button">
318 sub GetFrameworksLoop {
319 my $frameworkcode = shift;
320 my $frameworks = getframeworks();
322 foreach my $thisframework (sort { uc($frameworks->{$a}->{'frameworktext'}) cmp uc($frameworks->{$b}->{'frameworktext'}) } keys %$frameworks) {
323 my $selected = ( $thisframework eq $frameworkcode ) ? 1 : undef;
325 value => $thisframework,
326 selected => $selected,
327 description => $frameworks->{$thisframework}->{'frameworktext'},
329 push @frameworkloop, \%row;
331 return \@frameworkloop;
334 =head2 getframeworkinfo
336 $frameworkinfo = &getframeworkinfo($frameworkcode);
338 Returns information about an frameworkcode.
342 sub getframeworkinfo {
343 my ($frameworkcode) = @_;
344 my $dbh = C4::Context->dbh;
346 $dbh->prepare("select * from biblio_framework where frameworkcode=?");
347 $sth->execute($frameworkcode);
348 my $res = $sth->fetchrow_hashref;
352 =head2 getitemtypeinfo
354 $itemtype = &getitemtypeinfo($itemtype, [$interface]);
356 Returns information about an itemtype. The optional $interface argument
357 sets which interface ('opac' or 'intranet') to return the imageurl for.
358 Defaults to intranet.
362 sub getitemtypeinfo {
363 my ($itemtype, $interface) = @_;
364 my $dbh = C4::Context->dbh;
365 require C4::Languages;
366 my $language = C4::Languages::getlanguage();
367 my $it = $dbh->selectrow_hashref(q|
370 itemtypes.description,
371 itemtypes.rentalcharge,
372 itemtypes.notforloan,
375 itemtypes.checkinmsg,
376 itemtypes.checkinmsgtype,
377 itemtypes.sip_media_type,
378 COALESCE( localization.translation, itemtypes.description ) AS translated_description
380 LEFT JOIN localization ON itemtypes.itemtype = localization.code
381 AND localization.entity = 'itemtypes'
382 AND localization.lang = ?
383 WHERE itemtypes.itemtype = ?
384 |, undef, $language, $itemtype );
386 $it->{imageurl} = getitemtypeimagelocation( ( ( defined $interface && $interface eq 'opac' ) ? 'opac' : 'intranet' ), $it->{imageurl} );
391 =head2 getitemtypeimagedir
393 my $directory = getitemtypeimagedir( 'opac' );
395 pass in 'opac' or 'intranet'. Defaults to 'opac'.
397 returns the full path to the appropriate directory containing images.
401 sub getitemtypeimagedir {
402 my $src = shift || 'opac';
403 if ($src eq 'intranet') {
404 return C4::Context->config('intrahtdocs') . '/' .C4::Context->preference('template') . '/img/itemtypeimg';
406 return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
410 sub getitemtypeimagesrc {
411 my $src = shift || 'opac';
412 if ($src eq 'intranet') {
413 return '/intranet-tmpl' . '/' . C4::Context->preference('template') . '/img/itemtypeimg';
415 return '/opac-tmpl' . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
419 sub getitemtypeimagelocation {
420 my ( $src, $image ) = @_;
422 return '' if ( !$image );
425 my $scheme = ( URI::Split::uri_split( $image ) )[0];
427 return $image if ( $scheme );
429 return getitemtypeimagesrc( $src ) . '/' . $image;
432 =head3 _getImagesFromDirectory
434 Find all of the image files in a directory in the filesystem
436 parameters: a directory name
438 returns: a list of images in that directory.
440 Notes: this does not traverse into subdirectories. See
441 _getSubdirectoryNames for help with that.
442 Images are assumed to be files with .gif or .png file extensions.
443 The image names returned do not have the directory name on them.
447 sub _getImagesFromDirectory {
448 my $directoryname = shift;
449 return unless defined $directoryname;
450 return unless -d $directoryname;
452 if ( opendir ( my $dh, $directoryname ) ) {
453 my @images = grep { /\.(gif|png)$/i } readdir( $dh );
455 @images = sort(@images);
458 warn "unable to opendir $directoryname: $!";
463 =head3 _getSubdirectoryNames
465 Find all of the directories in a directory in the filesystem
467 parameters: a directory name
469 returns: a list of subdirectories in that directory.
471 Notes: this does not traverse into subdirectories. Only the first
472 level of subdirectories are returned.
473 The directory names returned don't have the parent directory name on them.
477 sub _getSubdirectoryNames {
478 my $directoryname = shift;
479 return unless defined $directoryname;
480 return unless -d $directoryname;
482 if ( opendir ( my $dh, $directoryname ) ) {
483 my @directories = grep { -d File::Spec->catfile( $directoryname, $_ ) && ! ( /^\./ ) } readdir( $dh );
487 warn "unable to opendir $directoryname: $!";
494 returns: a listref of hashrefs. Each hash represents another collection of images.
496 { imagesetname => 'npl', # the name of the image set (npl is the original one)
497 images => listref of image hashrefs
500 each image is represented by a hashref like this:
502 { KohaImage => 'npl/image.gif',
503 StaffImageUrl => '/intranet-tmpl/prog/img/itemtypeimg/npl/image.gif',
504 OpacImageURL => '/opac-tmpl/prog/itemtypeimg/npl/image.gif'
505 checked => 0 or 1: was this the image passed to this method?
506 Note: I'd like to remove this somehow.
513 my $checked = $params{'checked'} || '';
515 my $paths = { staff => { filesystem => getitemtypeimagedir('intranet'),
516 url => getitemtypeimagesrc('intranet'),
518 opac => { filesystem => getitemtypeimagedir('opac'),
519 url => getitemtypeimagesrc('opac'),
523 my @imagesets = (); # list of hasrefs of image set data to pass to template
524 my @subdirectories = _getSubdirectoryNames( $paths->{'staff'}{'filesystem'} );
525 foreach my $imagesubdir ( @subdirectories ) {
526 warn $imagesubdir if $DEBUG;
527 my @imagelist = (); # hashrefs of image info
528 my @imagenames = _getImagesFromDirectory( File::Spec->catfile( $paths->{'staff'}{'filesystem'}, $imagesubdir ) );
529 my $imagesetactive = 0;
530 foreach my $thisimage ( @imagenames ) {
532 { KohaImage => "$imagesubdir/$thisimage",
533 StaffImageUrl => join( '/', $paths->{'staff'}{'url'}, $imagesubdir, $thisimage ),
534 OpacImageUrl => join( '/', $paths->{'opac'}{'url'}, $imagesubdir, $thisimage ),
535 checked => "$imagesubdir/$thisimage" eq $checked ? 1 : 0,
538 $imagesetactive = 1 if "$imagesubdir/$thisimage" eq $checked;
540 push @imagesets, { imagesetname => $imagesubdir,
541 imagesetactive => $imagesetactive,
542 images => \@imagelist };
550 $printers = &GetPrinters();
551 @queues = keys %$printers;
553 Returns information about existing printer queues.
555 C<$printers> is a reference-to-hash whose keys are the print queues
556 defined in the printers table of the Koha database. The values are
557 references-to-hash, whose keys are the fields in the printers table.
563 my $dbh = C4::Context->dbh;
564 my $sth = $dbh->prepare("select * from printers");
566 while ( my $printer = $sth->fetchrow_hashref ) {
567 $printers{ $printer->{'printqueue'} } = $printer;
569 return ( \%printers );
574 $printer = GetPrinter( $query, $printers );
579 my ( $query, $printers ) = @_; # get printer for this query from printers
580 my $printer = $query->param('printer');
581 my %cookie = $query->cookie('userenv');
582 ($printer) || ( $printer = $cookie{'printer'} ) || ( $printer = '' );
583 ( $printers->{$printer} ) || ( $printer = ( keys %$printers )[0] );
589 Returns the number of pages to display in a pagination bar, given the number
590 of items and the number of items per page.
595 my ( $nb_items, $nb_items_per_page ) = @_;
597 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
602 (@themes) = &getallthemes('opac');
603 (@themes) = &getallthemes('intranet');
605 Returns an array of all available themes.
613 if ( $type eq 'intranet' ) {
614 $htdocs = C4::Context->config('intrahtdocs');
617 $htdocs = C4::Context->config('opachtdocs');
619 opendir D, "$htdocs";
620 my @dirlist = readdir D;
621 foreach my $directory (@dirlist) {
622 next if $directory eq 'lib';
623 -d "$htdocs/$directory/en" and push @themes, $directory;
630 if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
635 tags => [ qw/ 600ab 601ab 602a 604at 605a 606ax 610a / ],
641 tags => [ qw/ 607a / ],
647 tags => [ qw/ 500a 501a 503a / ],
653 tags => [ qw/ 700ab 701ab 702ab / ],
654 sep => C4::Context->preference("UNIMARCAuthorsFacetsSeparator"),
659 tags => [ qw/ 225a / ],
665 tags => [ qw/ 995e / ],
669 unless ( Koha::Libraries->search->count == 1 )
671 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
672 if ( $DisplayLibraryFacets eq 'both'
673 || $DisplayLibraryFacets eq 'holding' )
678 idx => 'holdingbranch',
679 label => 'HoldingLibrary',
680 tags => [qw / 995c /],
685 if ( $DisplayLibraryFacets eq 'both'
686 || $DisplayLibraryFacets eq 'home' )
692 label => 'HomeLibrary',
693 tags => [qw / 995b /],
704 tags => [ qw/ 650a / ],
709 # label => 'People and Organizations',
710 # tags => [ qw/ 600a 610a 611a / ],
716 tags => [ qw/ 651a / ],
722 tags => [ qw/ 630a / ],
728 tags => [ qw/ 100a 110a 700a / ],
734 tags => [ qw/ 440a 490a / ],
739 label => 'ItemTypes',
740 tags => [ qw/ 952y 942c / ],
746 tags => [ qw / 952c / ],
750 unless ( Koha::Libraries->search->count == 1 )
752 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
753 if ( $DisplayLibraryFacets eq 'both'
754 || $DisplayLibraryFacets eq 'holding' )
759 idx => 'holdingbranch',
760 label => 'HoldingLibrary',
761 tags => [qw / 952b /],
766 if ( $DisplayLibraryFacets eq 'both'
767 || $DisplayLibraryFacets eq 'home' )
773 label => 'HomeLibrary',
774 tags => [qw / 952a /],
785 Return a href where a key is associated to a href. You give a query,
786 the name of the key among the fields returned by the query. If you
787 also give as third argument the name of the value, the function
788 returns a href of scalar. The optional 4th argument is an arrayref of
789 items passed to the C<execute()> call. It is designed to bind
790 parameters to any placeholders in your SQL.
799 # generic href of any information on the item, href of href.
800 my $iteminfos_of = get_infos_of($query, 'itemnumber');
801 print $iteminfos_of->{$itemnumber}{barcode};
803 # specific information, href of scalar
804 my $barcode_of_item = get_infos_of($query, 'itemnumber', 'barcode');
805 print $barcode_of_item->{$itemnumber};
810 my ( $query, $key_name, $value_name, $bind_params ) = @_;
812 my $dbh = C4::Context->dbh;
814 my $sth = $dbh->prepare($query);
815 $sth->execute( @$bind_params );
818 while ( my $row = $sth->fetchrow_hashref ) {
819 if ( defined $value_name ) {
820 $infos_of{ $row->{$key_name} } = $row->{$value_name};
823 $infos_of{ $row->{$key_name} } = $row;
831 =head2 get_notforloan_label_of
833 my $notforloan_label_of = get_notforloan_label_of();
835 Each authorised value of notforloan (information available in items and
836 itemtypes) is link to a single label.
838 Returns a href where keys are authorised values and values are corresponding
841 foreach my $authorised_value (keys %{$notforloan_label_of}) {
843 "authorised_value: %s => %s\n",
845 $notforloan_label_of->{$authorised_value}
851 # FIXME - why not use GetAuthorisedValues ??
853 sub get_notforloan_label_of {
854 my $dbh = C4::Context->dbh;
857 SELECT authorised_value
858 FROM marc_subfield_structure
859 WHERE kohafield = \'items.notforloan\'
862 my $sth = $dbh->prepare($query);
864 my ($statuscode) = $sth->fetchrow_array();
869 FROM authorised_values
872 $sth = $dbh->prepare($query);
873 $sth->execute($statuscode);
874 my %notforloan_label_of;
875 while ( my $row = $sth->fetchrow_hashref ) {
876 $notforloan_label_of{ $row->{authorised_value} } = $row->{lib};
880 return \%notforloan_label_of;
883 =head2 GetAuthValCode
885 $authvalcode = GetAuthValCode($kohafield,$frameworkcode);
890 my ($kohafield,$fwcode) = @_;
891 my $dbh = C4::Context->dbh;
892 $fwcode='' unless $fwcode;
893 my $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield=? and frameworkcode=?');
894 $sth->execute($kohafield,$fwcode);
895 my ($authvalcode) = $sth->fetchrow_array;
899 =head2 GetAuthorisedValues
901 $authvalues = GetAuthorisedValues([$category]);
903 This function returns all authorised values from the'authorised_value' table in a reference to array of hashrefs.
905 C<$category> returns authorised values for just one category (optional).
907 C<$opac> If set to a true value, displays OPAC descriptions rather than normal ones when they exist.
911 sub GetAuthorisedValues {
912 my ( $category, $opac ) = @_;
914 # Is this cached already?
915 $opac = $opac ? 1 : 0; # normalise to be safe
917 C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
919 "AuthorisedValues-$category-$opac-$branch_limit";
920 my $cache = Koha::Caches->get_instance();
921 my $result = $cache->get_from_cache($cache_key);
922 return $result if $result;
925 my $dbh = C4::Context->dbh;
928 FROM authorised_values av
931 LEFT JOIN authorised_values_branches ON ( id = av_id )
936 push @where_strings, "category = ?";
937 push @where_args, $category;
940 push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
941 push @where_args, $branch_limit;
943 if(@where_strings > 0) {
944 $query .= " WHERE " . join(" AND ", @where_strings);
946 $query .= ' ORDER BY category, ' . (
947 $opac ? 'COALESCE(lib_opac, lib)'
951 my $sth = $dbh->prepare($query);
953 $sth->execute( @where_args );
954 while (my $data=$sth->fetchrow_hashref) {
955 if ($opac && $data->{lib_opac}) {
956 $data->{lib} = $data->{lib_opac};
958 push @results, $data;
962 $cache->set_in_cache( $cache_key, \@results, { expiry => 5 } );
966 =head2 GetAuthorisedValueCategories
968 $auth_categories = GetAuthorisedValueCategories();
970 Return an arrayref of all of the available authorised
975 sub GetAuthorisedValueCategories {
976 my $dbh = C4::Context->dbh;
977 my $sth = $dbh->prepare("SELECT DISTINCT category FROM authorised_values ORDER BY category");
980 while (defined (my $category = $sth->fetchrow_array) ) {
981 push @results, $category;
986 =head2 GetAuthorisedValueByCode
988 $authorised_value = GetAuthorisedValueByCode( $category, $authvalcode, $opac );
990 Return the lib attribute from authorised_values from the row identified
991 by the passed category and code
995 sub GetAuthorisedValueByCode {
996 my ( $category, $authvalcode, $opac ) = @_;
998 my $field = $opac ? 'lib_opac' : 'lib';
999 my $dbh = C4::Context->dbh;
1000 my $sth = $dbh->prepare("SELECT $field FROM authorised_values WHERE category=? AND authorised_value =?");
1001 $sth->execute( $category, $authvalcode );
1002 while ( my $data = $sth->fetchrow_hashref ) {
1003 return $data->{ $field };
1007 =head2 GetKohaAuthorisedValues
1009 Takes $kohafield, $fwcode as parameters.
1011 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1013 Returns hashref of Code => description
1015 Returns undef if no authorised value category is defined for the kohafield.
1019 sub GetKohaAuthorisedValues {
1020 my ($kohafield,$fwcode,$opac) = @_;
1021 $fwcode='' unless $fwcode;
1023 my $dbh = C4::Context->dbh;
1024 my $avcode = GetAuthValCode($kohafield,$fwcode);
1026 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1027 $sth->execute($avcode);
1028 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1029 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1037 =head2 GetKohaAuthorisedValuesMapping
1039 Takes a hash as a parameter. The interface key indicates the
1040 description to use in the mapping.
1043 "{kohafield},{frameworkcode},{authorised_value}" => "{description}"
1044 for all the kohafields, frameworkcodes, and authorised values.
1046 Returns undef if nothing is found.
1050 sub GetKohaAuthorisedValuesMapping {
1051 my ($parameter) = @_;
1052 my $interface = $parameter->{'interface'} // '';
1054 my $query_mapping = q{
1055 SELECT TA.kohafield,TA.authorised_value AS category,
1056 TA.frameworkcode,TB.authorised_value,
1057 IF(TB.lib_opac>'',TB.lib_opac,TB.lib) AS OPAC,
1058 TB.lib AS Intranet,TB.lib_opac
1059 FROM marc_subfield_structure AS TA JOIN
1060 authorised_values as TB ON
1061 TA.authorised_value=TB.category
1062 WHERE TA.kohafield>'' AND TA.authorised_value>'';
1064 my $dbh = C4::Context->dbh;
1065 my $sth = $dbh->prepare($query_mapping);
1068 if ($interface eq 'opac') {
1069 while (my $row = $sth->fetchrow_hashref) {
1070 $avmapping->{$row->{kohafield}.",".$row->{frameworkcode}.",".$row->{authorised_value}} = $row->{OPAC};
1074 while (my $row = $sth->fetchrow_hashref) {
1075 $avmapping->{$row->{kohafield}.",".$row->{frameworkcode}.",".$row->{authorised_value}} = $row->{Intranet};
1083 my $escaped_string = C4::Koha::xml_escape($string);
1085 Convert &, <, >, ', and " in a string to XML entities
1091 return '' unless defined $str;
1092 $str =~ s/&/&/g;
1095 $str =~ s/'/'/g;
1096 $str =~ s/"/"/g;
1100 =head2 display_marc_indicators
1102 my $display_form = C4::Koha::display_marc_indicators($field);
1104 C<$field> is a MARC::Field object
1106 Generate a display form of the indicators of a variable
1107 MARC field, replacing any blanks with '#'.
1111 sub display_marc_indicators {
1113 my $indicators = '';
1114 if ($field && $field->tag() >= 10) {
1115 $indicators = $field->indicator(1) . $field->indicator(2);
1116 $indicators =~ s/ /#/g;
1121 sub GetNormalizedUPC {
1122 my ($marcrecord,$marcflavour) = @_;
1124 return unless $marcrecord;
1125 if ($marcflavour eq 'UNIMARC') {
1126 my @fields = $marcrecord->field('072');
1127 foreach my $field (@fields) {
1128 my $upc = _normalize_match_point($field->subfield('a'));
1135 else { # assume marc21 if not unimarc
1136 my @fields = $marcrecord->field('024');
1137 foreach my $field (@fields) {
1138 my $indicator = $field->indicator(1);
1139 my $upc = _normalize_match_point($field->subfield('a'));
1140 if ($upc && $indicator == 1 ) {
1147 # Normalizes and returns the first valid ISBN found in the record
1148 # ISBN13 are converted into ISBN10. This is required to get some book cover images.
1149 sub GetNormalizedISBN {
1150 my ($isbn,$marcrecord,$marcflavour) = @_;
1152 # Koha attempts to store multiple ISBNs in biblioitems.isbn, separated by " | "
1153 # anything after " | " should be removed, along with the delimiter
1154 ($isbn) = split(/\|/, $isbn );
1155 return _isbn_cleanup($isbn);
1158 return unless $marcrecord;
1160 if ($marcflavour eq 'UNIMARC') {
1161 my @fields = $marcrecord->field('010');
1162 foreach my $field (@fields) {
1163 my $isbn = $field->subfield('a');
1165 return _isbn_cleanup($isbn);
1169 else { # assume marc21 if not unimarc
1170 my @fields = $marcrecord->field('020');
1171 foreach my $field (@fields) {
1172 $isbn = $field->subfield('a');
1174 return _isbn_cleanup($isbn);
1180 sub GetNormalizedEAN {
1181 my ($marcrecord,$marcflavour) = @_;
1183 return unless $marcrecord;
1185 if ($marcflavour eq 'UNIMARC') {
1186 my @fields = $marcrecord->field('073');
1187 foreach my $field (@fields) {
1188 my $ean = _normalize_match_point($field->subfield('a'));
1194 else { # assume marc21 if not unimarc
1195 my @fields = $marcrecord->field('024');
1196 foreach my $field (@fields) {
1197 my $indicator = $field->indicator(1);
1198 my $ean = _normalize_match_point($field->subfield('a'));
1199 if ( $ean && $indicator == 3 ) {
1206 sub GetNormalizedOCLCNumber {
1207 my ($marcrecord,$marcflavour) = @_;
1208 return unless $marcrecord;
1210 if ($marcflavour ne 'UNIMARC' ) {
1211 my @fields = $marcrecord->field('035');
1212 foreach my $field (@fields) {
1213 my $oclc = $field->subfield('a');
1214 if ($oclc =~ /OCoLC/) {
1215 $oclc =~ s/\(OCoLC\)//;
1225 sub GetAuthvalueDropbox {
1226 my ( $authcat, $default ) = @_;
1227 my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
1228 my $dbh = C4::Context->dbh;
1232 FROM authorised_values
1235 LEFT JOIN authorised_values_branches ON ( id = av_id )
1240 $query .= " AND ( branchcode = ? OR branchcode IS NULL )" if $branch_limit;
1241 $query .= " GROUP BY lib ORDER BY category, lib, lib_opac";
1242 my $sth = $dbh->prepare($query);
1243 $sth->execute( $authcat, $branch_limit ? $branch_limit : () );
1246 my $option_list = [];
1247 my @authorised_values = ( q{} );
1248 while (my $av = $sth->fetchrow_hashref) {
1249 push @{$option_list}, {
1250 value => $av->{authorised_value},
1251 label => $av->{lib},
1252 default => ($default eq $av->{authorised_value}),
1256 if ( @{$option_list} ) {
1257 return $option_list;
1263 =head2 GetDailyQuote($opts)
1265 Takes a hashref of options
1267 Currently supported options are:
1269 'id' An exact quote id
1270 'random' Select a random quote
1271 noop When no option is passed in, this sub will return the quote timestamped for the current day
1273 The function returns an anonymous hash following this format:
1276 'source' => 'source-of-quote',
1277 'timestamp' => 'timestamp-value',
1278 'text' => 'text-of-quote',
1284 # This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
1285 # at least for default option
1289 my $dbh = C4::Context->dbh;
1294 $query = 'SELECT * FROM quotes WHERE id = ?';
1295 $sth = $dbh->prepare($query);
1296 $sth->execute($opts{'id'});
1297 $quote = $sth->fetchrow_hashref();
1299 elsif ($opts{'random'}) {
1300 # Fall through... we also return a random quote as a catch-all if all else fails
1303 $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp DESC LIMIT 0,1';
1304 $sth = $dbh->prepare($query);
1306 $quote = $sth->fetchrow_hashref();
1308 unless ($quote) { # if there are not matches, choose a random quote
1309 # get a list of all available quote ids
1310 $sth = C4::Context->dbh->prepare('SELECT count(*) FROM quotes;');
1312 my $range = ($sth->fetchrow_array)[0];
1313 # chose a random id within that range if there is more than one quote
1314 my $offset = int(rand($range));
1316 $query = 'SELECT * FROM quotes ORDER BY id LIMIT 1 OFFSET ?';
1317 $sth = C4::Context->dbh->prepare($query);
1318 # see http://www.perlmonks.org/?node_id=837422 for why
1319 # we're being verbose and using bind_param
1320 $sth->bind_param(1, $offset, SQL_INTEGER);
1322 $quote = $sth->fetchrow_hashref();
1323 # update the timestamp for that quote
1324 $query = 'UPDATE quotes SET timestamp = ? WHERE id = ?';
1325 $sth = C4::Context->dbh->prepare($query);
1327 DateTime::Format::MySQL->format_datetime( dt_from_string() ),
1334 sub _normalize_match_point {
1335 my $match_point = shift;
1336 (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
1337 $normalized_match_point =~ s/-//g;
1339 return $normalized_match_point;
1344 return NormalizeISBN(
1347 format => 'ISBN-10',
1353 =head2 NormalizedISBN
1355 my $isbns = NormalizedISBN({
1357 strip_hyphens => [0,1],
1358 format => ['ISBN-10', 'ISBN-13']
1361 Returns an isbn validated by Business::ISBN.
1362 Optionally strips hyphens and/or forces the isbn
1363 to be of the specified format.
1365 If the string cannot be validated as an isbn,
1373 my $string = $params->{isbn};
1374 my $strip_hyphens = $params->{strip_hyphens};
1375 my $format = $params->{format};
1377 return unless $string;
1379 my $isbn = Business::ISBN->new($string);
1381 if ( $isbn && $isbn->is_valid() ) {
1383 if ( $format eq 'ISBN-10' ) {
1384 $isbn = $isbn->as_isbn10();
1386 elsif ( $format eq 'ISBN-13' ) {
1387 $isbn = $isbn->as_isbn13();
1389 return unless $isbn;
1391 if ($strip_hyphens) {
1392 $string = $isbn->as_string( [] );
1394 $string = $isbn->as_string();
1401 =head2 GetVariationsOfISBN
1403 my @isbns = GetVariationsOfISBN( $isbn );
1405 Returns a list of variations of the given isbn in
1406 both ISBN-10 and ISBN-13 formats, with and without
1409 In a scalar context, the isbns are returned as a
1410 string delimited by ' | '.
1414 sub GetVariationsOfISBN {
1417 return unless $isbn;
1421 push( @isbns, NormalizeISBN({ isbn => $isbn }) );
1422 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10' }) );
1423 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13' }) );
1424 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10', strip_hyphens => 1 }) );
1425 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13', strip_hyphens => 1 }) );
1427 # Strip out any "empty" strings from the array
1428 @isbns = grep { defined($_) && $_ =~ /\S/ } @isbns;
1430 return wantarray ? @isbns : join( " | ", @isbns );
1433 =head2 GetVariationsOfISBNs
1435 my @isbns = GetVariationsOfISBNs( @isbns );
1437 Returns a list of variations of the given isbns in
1438 both ISBN-10 and ISBN-13 formats, with and without
1441 In a scalar context, the isbns are returned as a
1442 string delimited by ' | '.
1446 sub GetVariationsOfISBNs {
1449 @isbns = map { GetVariationsOfISBN( $_ ) } @isbns;
1451 return wantarray ? @isbns : join( " | ", @isbns );
1454 =head2 IsKohaFieldLinked
1456 my $is_linked = IsKohaFieldLinked({
1457 kohafield => $kohafield,
1458 frameworkcode => $frameworkcode,
1461 Return 1 if the field is linked
1465 sub IsKohaFieldLinked {
1466 my ( $params ) = @_;
1467 my $kohafield = $params->{kohafield};
1468 my $frameworkcode = $params->{frameworkcode} || '';
1469 my $dbh = C4::Context->dbh;
1470 my $is_linked = $dbh->selectcol_arrayref( q|
1472 FROM marc_subfield_structure
1473 WHERE frameworkcode = ?
1475 |,{}, $frameworkcode, $kohafield );
1476 return $is_linked->[0];