3 # Copyright 2000-2002 Katipo Communications
4 # Parts Copyright 2010 Nelsonville Public Library
5 # Parts copyright 2010 BibLibre
7 # This file is part of Koha.
9 # Koha is free software; you can redistribute it and/or modify it under the
10 # terms of the GNU General Public License as published by the Free Software
11 # Foundation; either version 2 of the License, or (at your option) any later
14 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License along
19 # with Koha; if not, write to the Free Software Foundation, Inc.,
20 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #use warnings; FIXME - Bug 2505
27 use C4
::Branch
qw(GetBranchesCount);
28 use Koha
::DateUtils
qw(dt_from_string);
30 use DateTime
::Format
::MySQL
;
32 use autouse
'Data::Dumper' => qw(Dumper);
33 use DBI
qw(:sql_types);
35 use vars
qw($VERSION @ISA @EXPORT @EXPORT_OK $DEBUG);
38 $VERSION = 3.07.00.049;
43 &subfield_is_koha_internal_p
44 &GetPrinters &GetPrinter
45 &GetItemTypes &getitemtypeinfo
46 &GetSupportName &GetSupportList
48 &getframeworks &getframeworkinfo
49 &getauthtypes &getauthtype
55 &get_notforloan_label_of
58 &getitemtypeimagelocation
60 &GetAuthorisedValueCategories
61 &IsAuthorisedValueCategory
62 &GetKohaAuthorisedValues
63 &GetKohaAuthorisedValuesFromField
64 &GetKohaAuthorisedValueLib
65 &GetAuthorisedValueByCode
66 &GetKohaImageurlFromAuthorisedValues
72 &GetNormalizedOCLCNumber
82 @EXPORT_OK = qw( GetDailyQuote );
86 memoize
('GetAuthorisedValues');
90 C4::Koha - Perl Module containing convenience functions for Koha scripts
98 Koha.pm provides many functions for Koha scripts.
106 $slash_date = &slashifyDate($dash_date);
108 Takes a string of the form "DD-MM-YYYY" (or anything separated by
109 dashes), converts it to the form "YYYY/MM/DD", and returns the result.
115 # accepts a date of the form xx-xx-xx[xx] and returns it in the
117 my @dateOut = split( '-', shift );
118 return ("$dateOut[2]/$dateOut[1]/$dateOut[0]");
121 # FIXME.. this should be moved to a MARC-specific module
122 sub subfield_is_koha_internal_p
{
125 # We could match on 'lib' and 'tab' (and 'mandatory', & more to come!)
126 # But real MARC subfields are always single-character
127 # so it really is safer just to check the length
129 return length $subfield != 1;
132 =head2 GetSupportName
134 $itemtypename = &GetSupportName($codestring);
136 Returns a string with the name of the itemtype.
142 return if (! $codestring);
144 my $advanced_search_types = C4
::Context
->preference("AdvancedSearchTypes");
145 if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') {
152 my $sth = C4
::Context
->dbh->prepare($query);
153 $sth->execute($codestring);
154 ($resultstring)=$sth->fetchrow;
155 return $resultstring;
158 C4
::Context
->dbh->prepare(
159 "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
161 $sth->execute( $advanced_search_types, $codestring );
162 my $data = $sth->fetchrow_hashref;
163 return $$data{'lib'};
167 =head2 GetSupportList
169 $itemtypes = &GetSupportList();
171 Returns an array ref containing informations about Support (since itemtype is rather a circulation code when item-level-itypes is used).
173 build a HTML select with the following code :
175 =head3 in PERL SCRIPT
177 my $itemtypes = GetSupportList();
178 $template->param(itemtypeloop => $itemtypes);
182 <select name="itemtype" id="itemtype">
183 <option value=""></option>
184 [% FOREACH itemtypeloo IN itemtypeloop %]
185 [% IF ( itemtypeloo.selected ) %]
186 <option value="[% itemtypeloo.itemtype %]" selected="selected">[% itemtypeloo.description %]</option>
188 <option value="[% itemtypeloo.itemtype %]">[% itemtypeloo.description %]</option>
196 my $advanced_search_types = C4
::Context
->preference("AdvancedSearchTypes");
197 if (!$advanced_search_types or $advanced_search_types =~ /itemtypes/) {
203 my $sth = C4
::Context
->dbh->prepare($query);
205 return $sth->fetchall_arrayref({});
207 my $advsearchtypes = GetAuthorisedValues
($advanced_search_types);
208 my @results= map {{itemtype
=>$$_{authorised_value
},description
=>$$_{lib
},imageurl
=>$$_{imageurl
}}} @
$advsearchtypes;
214 $itemtypes = &GetItemTypes( style => $style );
216 Returns information about existing itemtypes.
219 style: either 'array' or 'hash', defaults to 'hash'.
220 'array' returns an arrayref,
221 'hash' return a hashref with the itemtype value as the key
223 build a HTML select with the following code :
225 =head3 in PERL SCRIPT
227 my $itemtypes = GetItemTypes;
229 foreach my $thisitemtype (sort keys %$itemtypes) {
230 my $selected = 1 if $thisitemtype eq $itemtype;
231 my %row =(value => $thisitemtype,
232 selected => $selected,
233 description => $itemtypes->{$thisitemtype}->{'description'},
235 push @itemtypesloop, \%row;
237 $template->param(itemtypeloop => \@itemtypesloop);
241 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
242 <select name="itemtype">
243 <option value="">Default</option>
244 <!-- TMPL_LOOP name="itemtypeloop" -->
245 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="description" --></option>
248 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
249 <input type="submit" value="OK" class="button">
256 my $style = defined( $params{'style'} ) ?
$params{'style'} : 'hash';
258 # returns a reference to a hash of references to itemtypes...
260 my $dbh = C4
::Context
->dbh;
265 my $sth = $dbh->prepare($query);
268 if ( $style eq 'hash' ) {
269 while ( my $IT = $sth->fetchrow_hashref ) {
270 $itemtypes{ $IT->{'itemtype'} } = $IT;
272 return ( \
%itemtypes );
274 return $sth->fetchall_arrayref({});
278 sub get_itemtypeinfos_of
{
281 my $placeholders = join( ', ', map { '?' } @itemtypes );
282 my $query = <<"END_SQL";
288 WHERE itemtype IN ( $placeholders )
291 return get_infos_of( $query, 'itemtype', undef, \@itemtypes );
296 $authtypes = &getauthtypes();
298 Returns information about existing authtypes.
300 build a HTML select with the following code :
302 =head3 in PERL SCRIPT
304 my $authtypes = getauthtypes;
306 foreach my $thisauthtype (keys %$authtypes) {
307 my $selected = 1 if $thisauthtype eq $authtype;
308 my %row =(value => $thisauthtype,
309 selected => $selected,
310 authtypetext => $authtypes->{$thisauthtype}->{'authtypetext'},
312 push @authtypesloop, \%row;
314 $template->param(itemtypeloop => \@itemtypesloop);
318 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
319 <select name="authtype">
320 <!-- TMPL_LOOP name="authtypeloop" -->
321 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="authtypetext" --></option>
324 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
325 <input type="submit" value="OK" class="button">
333 # returns a reference to a hash of references to authtypes...
335 my $dbh = C4::Context->dbh;
336 my $sth = $dbh->prepare("select * from auth_types order by authtypetext");
338 while ( my $IT = $sth->fetchrow_hashref ) {
339 $authtypes{ $IT->{'authtypecode'} } = $IT;
341 return ( \%authtypes );
345 my ($authtypecode) = @_;
347 # returns a reference to a hash of references to authtypes...
349 my $dbh = C4::Context->dbh;
350 my $sth = $dbh->prepare("select * from auth_types where authtypecode=?");
351 $sth->execute($authtypecode);
352 my $res = $sth->fetchrow_hashref;
358 $frameworks = &getframework();
360 Returns information about existing frameworks
362 build a HTML select with the following code :
364 =head3 in PERL SCRIPT
366 my $frameworks = frameworks();
368 foreach my $thisframework (keys %$frameworks) {
369 my $selected = 1 if $thisframework eq $frameworkcode;
370 my %row =(value => $thisframework,
371 selected => $selected,
372 description => $frameworks->{$thisframework}->{'frameworktext'},
374 push @frameworksloop, \%row;
376 $template->param(frameworkloop => \@frameworksloop);
380 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
381 <select name="frameworkcode">
382 <option value="">Default</option>
383 <!-- TMPL_LOOP name="frameworkloop" -->
384 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="frameworktext" --></option>
387 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
388 <input type="submit" value="OK" class="button">
395 # returns a reference to a hash of references to branches...
397 my $dbh = C4::Context->dbh;
398 my $sth = $dbh->prepare("select * from biblio_framework");
400 while ( my $IT = $sth->fetchrow_hashref ) {
401 $itemtypes{ $IT->{'frameworkcode'} } = $IT;
403 return ( \%itemtypes );
406 =head2 getframeworkinfo
408 $frameworkinfo = &getframeworkinfo($frameworkcode);
410 Returns information about an frameworkcode.
414 sub getframeworkinfo {
415 my ($frameworkcode) = @_;
416 my $dbh = C4::Context->dbh;
418 $dbh->prepare("select * from biblio_framework where frameworkcode=?");
419 $sth->execute($frameworkcode);
420 my $res = $sth->fetchrow_hashref;
424 =head2 getitemtypeinfo
426 $itemtype = &getitemtypeinfo($itemtype, [$interface]);
428 Returns information about an itemtype. The optional $interface argument
429 sets which interface ('opac' or 'intranet') to return the imageurl for.
430 Defaults to intranet.
434 sub getitemtypeinfo {
435 my ($itemtype, $interface) = @_;
436 my $dbh = C4::Context->dbh;
437 my $sth = $dbh->prepare("select * from itemtypes where itemtype=?");
438 $sth->execute($itemtype);
439 my $res = $sth->fetchrow_hashref;
441 $res->{imageurl} = getitemtypeimagelocation( ( ( defined $interface && $interface eq 'opac' ) ? 'opac' : 'intranet' ), $res->{imageurl} );
446 =head2 getitemtypeimagedir
448 my $directory = getitemtypeimagedir( 'opac' );
450 pass in 'opac' or 'intranet'. Defaults to 'opac'.
452 returns the full path to the appropriate directory containing images.
456 sub getitemtypeimagedir {
457 my $src = shift || 'opac';
458 if ($src eq 'intranet') {
459 return C4::Context->config('intrahtdocs') . '/' .C4::Context->preference('template') . '/img/itemtypeimg';
461 return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
465 sub getitemtypeimagesrc {
466 my $src = shift || 'opac';
467 if ($src eq 'intranet') {
468 return '/intranet-tmpl' . '/' . C4::Context->preference('template') . '/img/itemtypeimg';
470 return '/opac-tmpl' . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
474 sub getitemtypeimagelocation {
475 my ( $src, $image ) = @_;
477 return '' if ( !$image );
480 my $scheme = ( URI::Split::uri_split( $image ) )[0];
482 return $image if ( $scheme );
484 return getitemtypeimagesrc( $src ) . '/' . $image;
487 =head3 _getImagesFromDirectory
489 Find all of the image files in a directory in the filesystem
491 parameters: a directory name
493 returns: a list of images in that directory.
495 Notes: this does not traverse into subdirectories. See
496 _getSubdirectoryNames for help with that.
497 Images are assumed to be files with .gif or .png file extensions.
498 The image names returned do not have the directory name on them.
502 sub _getImagesFromDirectory {
503 my $directoryname = shift;
504 return unless defined $directoryname;
505 return unless -d $directoryname;
507 if ( opendir ( my $dh, $directoryname ) ) {
508 my @images = grep { /\.(gif|png)$/i } readdir( $dh );
510 @images = sort(@images);
513 warn "unable to opendir $directoryname: $!";
518 =head3 _getSubdirectoryNames
520 Find all of the directories in a directory in the filesystem
522 parameters: a directory name
524 returns: a list of subdirectories in that directory.
526 Notes: this does not traverse into subdirectories. Only the first
527 level of subdirectories are returned.
528 The directory names returned don't have the parent directory name on them.
532 sub _getSubdirectoryNames {
533 my $directoryname = shift;
534 return unless defined $directoryname;
535 return unless -d $directoryname;
537 if ( opendir ( my $dh, $directoryname ) ) {
538 my @directories = grep { -d File::Spec->catfile( $directoryname, $_ ) && ! ( /^\./ ) } readdir( $dh );
542 warn "unable to opendir $directoryname: $!";
549 returns: a listref of hashrefs. Each hash represents another collection of images.
551 { imagesetname => 'npl', # the name of the image set (npl is the original one)
552 images => listref of image hashrefs
555 each image is represented by a hashref like this:
557 { KohaImage => 'npl/image.gif',
558 StaffImageUrl => '/intranet-tmpl/prog/img/itemtypeimg/npl/image.gif',
559 OpacImageURL => '/opac-tmpl/prog/itemtypeimg/npl/image.gif'
560 checked => 0 or 1: was this the image passed to this method?
561 Note: I'd like to remove this somehow.
568 my $checked = $params{'checked'} || '';
570 my $paths = { staff => { filesystem => getitemtypeimagedir('intranet'),
571 url => getitemtypeimagesrc('intranet'),
573 opac => { filesystem => getitemtypeimagedir('opac'),
574 url => getitemtypeimagesrc('opac'),
578 my @imagesets = (); # list of hasrefs of image set data to pass to template
579 my @subdirectories = _getSubdirectoryNames( $paths->{'staff'}{'filesystem'} );
580 foreach my $imagesubdir ( @subdirectories ) {
581 warn $imagesubdir if $DEBUG;
582 my @imagelist = (); # hashrefs of image info
583 my @imagenames = _getImagesFromDirectory( File::Spec->catfile( $paths->{'staff'}{'filesystem'}, $imagesubdir ) );
584 my $imagesetactive = 0;
585 foreach my $thisimage ( @imagenames ) {
587 { KohaImage => "$imagesubdir/$thisimage",
588 StaffImageUrl => join( '/', $paths->{'staff'}{'url'}, $imagesubdir, $thisimage ),
589 OpacImageUrl => join( '/', $paths->{'opac'}{'url'}, $imagesubdir, $thisimage ),
590 checked => "$imagesubdir/$thisimage" eq $checked ? 1 : 0,
593 $imagesetactive = 1 if "$imagesubdir/$thisimage" eq $checked;
595 push @imagesets, { imagesetname => $imagesubdir,
596 imagesetactive => $imagesetactive,
597 images => \@imagelist };
605 $printers = &GetPrinters();
606 @queues = keys %$printers;
608 Returns information about existing printer queues.
610 C<$printers> is a reference-to-hash whose keys are the print queues
611 defined in the printers table of the Koha database. The values are
612 references-to-hash, whose keys are the fields in the printers table.
618 my $dbh = C4::Context->dbh;
619 my $sth = $dbh->prepare("select * from printers");
621 while ( my $printer = $sth->fetchrow_hashref ) {
622 $printers{ $printer->{'printqueue'} } = $printer;
624 return ( \%printers );
629 $printer = GetPrinter( $query, $printers );
634 my ( $query, $printers ) = @_; # get printer for this query from printers
635 my $printer = $query->param('printer');
636 my %cookie = $query->cookie('userenv');
637 ($printer) || ( $printer = $cookie{'printer'} ) || ( $printer = '' );
638 ( $printers->{$printer} ) || ( $printer = ( keys %$printers )[0] );
644 Returns the number of pages to display in a pagination bar, given the number
645 of items and the number of items per page.
650 my ( $nb_items, $nb_items_per_page ) = @_;
652 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
657 (@themes) = &getallthemes('opac');
658 (@themes) = &getallthemes('intranet');
660 Returns an array of all available themes.
668 if ( $type eq 'intranet' ) {
669 $htdocs = C4::Context->config('intrahtdocs');
672 $htdocs = C4::Context->config('opachtdocs');
674 opendir D, "$htdocs";
675 my @dirlist = readdir D;
676 foreach my $directory (@dirlist) {
677 next if $directory eq 'lib';
678 -d "$htdocs/$directory/en" and push @themes, $directory;
685 if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
690 tags => [ qw/ 600ab 601ab 602a 604at 605a 606ax 610a / ],
696 tags => [ qw/ 607a / ],
702 tags => [ qw/ 500a 501a 503a / ],
708 tags => [ qw/ 700ab 701ab 702ab / ],
709 sep => C4::Context->preference("UNIMARCAuthorsFacetsSeparator"),
714 tags => [ qw/ 225a / ],
720 tags => [ qw/ 995e / ],
724 unless ( C4::Context->preference("singleBranchMode")
725 || GetBranchesCount() == 1 )
727 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
728 if ( $DisplayLibraryFacets eq 'both'
729 || $DisplayLibraryFacets eq 'holding' )
734 idx => 'holdingbranch',
735 label => 'HoldingLibrary',
736 tags => [qw / 995b /],
741 if ( $DisplayLibraryFacets eq 'both'
742 || $DisplayLibraryFacets eq 'home' )
748 label => 'HomeLibrary',
749 tags => [qw / 995a /],
760 tags => [ qw/ 650a / ],
765 # label => 'People and Organizations',
766 # tags => [ qw/ 600a 610a 611a / ],
772 tags => [ qw/ 651a / ],
778 tags => [ qw/ 630a / ],
784 tags => [ qw/ 100a 110a 700a / ],
790 tags => [ qw/ 440a 490a / ],
795 label => 'ItemTypes',
796 tags => [ qw/ 952y 942c / ],
802 tags => [ qw / 952c / ],
806 unless ( C4::Context->preference("singleBranchMode")
807 || GetBranchesCount() == 1 )
809 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
810 if ( $DisplayLibraryFacets eq 'both'
811 || $DisplayLibraryFacets eq 'holding' )
816 idx => 'holdingbranch',
817 label => 'HoldingLibrary',
818 tags => [qw / 952b /],
823 if ( $DisplayLibraryFacets eq 'both'
824 || $DisplayLibraryFacets eq 'home' )
830 label => 'HomeLibrary',
831 tags => [qw / 952a /],
842 Return a href where a key is associated to a href. You give a query,
843 the name of the key among the fields returned by the query. If you
844 also give as third argument the name of the value, the function
845 returns a href of scalar. The optional 4th argument is an arrayref of
846 items passed to the C<execute()> call. It is designed to bind
847 parameters to any placeholders in your SQL.
856 # generic href of any information on the item, href of href.
857 my $iteminfos_of = get_infos_of($query, 'itemnumber');
858 print $iteminfos_of->{$itemnumber}{barcode};
860 # specific information, href of scalar
861 my $barcode_of_item = get_infos_of($query, 'itemnumber', 'barcode');
862 print $barcode_of_item->{$itemnumber};
867 my ( $query, $key_name, $value_name, $bind_params ) = @_;
869 my $dbh = C4::Context->dbh;
871 my $sth = $dbh->prepare($query);
872 $sth->execute( @$bind_params );
875 while ( my $row = $sth->fetchrow_hashref ) {
876 if ( defined $value_name ) {
877 $infos_of{ $row->{$key_name} } = $row->{$value_name};
880 $infos_of{ $row->{$key_name} } = $row;
888 =head2 get_notforloan_label_of
890 my $notforloan_label_of = get_notforloan_label_of();
892 Each authorised value of notforloan (information available in items and
893 itemtypes) is link to a single label.
895 Returns a href where keys are authorised values and values are corresponding
898 foreach my $authorised_value (keys %{$notforloan_label_of}) {
900 "authorised_value: %s => %s\n",
902 $notforloan_label_of->{$authorised_value}
908 # FIXME - why not use GetAuthorisedValues ??
910 sub get_notforloan_label_of {
911 my $dbh = C4::Context->dbh;
914 SELECT authorised_value
915 FROM marc_subfield_structure
916 WHERE kohafield = \'items.notforloan\'
919 my $sth = $dbh->prepare($query);
921 my ($statuscode) = $sth->fetchrow_array();
926 FROM authorised_values
929 $sth = $dbh->prepare($query);
930 $sth->execute($statuscode);
931 my %notforloan_label_of;
932 while ( my $row = $sth->fetchrow_hashref ) {
933 $notforloan_label_of{ $row->{authorised_value} } = $row->{lib};
937 return \%notforloan_label_of;
940 =head2 displayServers
942 my $servers = displayServers();
943 my $servers = displayServers( $position );
944 my $servers = displayServers( $position, $type );
946 displayServers returns a listref of hashrefs, each containing
947 information about available z3950 servers. Each hashref has a format
951 'checked' => 'checked',
952 'encoding' => 'utf8',
954 'id' => 'LIBRARY OF CONGRESS',
958 'value' => 'lx2.loc.gov:210/',
965 my ( $position, $type ) = @_;
966 my $dbh = C4::Context->dbh;
968 my $strsth = 'SELECT * FROM z3950servers';
973 push @bind_params, $position;
974 push @where_clauses, ' position = ? ';
978 push @bind_params, $type;
979 push @where_clauses, ' type = ? ';
982 # reassemble where clause from where clause pieces
983 if (@where_clauses) {
984 $strsth .= ' WHERE ' . join( ' AND ', @where_clauses );
987 my $rq = $dbh->prepare($strsth);
988 $rq->execute(@bind_params);
989 my @primaryserverloop;
991 while ( my $data = $rq->fetchrow_hashref ) {
992 push @primaryserverloop,
993 { label => $data->{description},
996 value => $data->{host} . ":" . $data->{port} . "/" . $data->{database},
997 encoding => ( $data->{encoding} ? $data->{encoding} : "iso-5426" ),
998 checked => "checked",
999 icon => $data->{icon},
1000 zed => $data->{type} eq 'zed',
1001 opensearch => $data->{type} eq 'opensearch'
1004 return \@primaryserverloop;
1008 =head2 GetKohaImageurlFromAuthorisedValues
1010 $authhorised_value = GetKohaImageurlFromAuthorisedValues( $category, $authvalcode );
1012 Return the first url of the authorised value image represented by $lib.
1016 sub GetKohaImageurlFromAuthorisedValues {
1017 my ( $category, $lib ) = @_;
1018 my $dbh = C4::Context->dbh;
1019 my $sth = $dbh->prepare("SELECT imageurl FROM authorised_values WHERE category=? AND lib =?");
1020 $sth->execute( $category, $lib );
1021 while ( my $data = $sth->fetchrow_hashref ) {
1022 return $data->{'imageurl'};
1026 =head2 GetAuthValCode
1028 $authvalcode = GetAuthValCode($kohafield,$frameworkcode);
1032 sub GetAuthValCode {
1033 my ($kohafield,$fwcode) = @_;
1034 my $dbh = C4::Context->dbh;
1035 $fwcode='' unless $fwcode;
1036 my $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield=? and frameworkcode=?');
1037 $sth->execute($kohafield,$fwcode);
1038 my ($authvalcode) = $sth->fetchrow_array;
1039 return $authvalcode;
1042 =head2 GetAuthValCodeFromField
1044 $authvalcode = GetAuthValCodeFromField($field,$subfield,$frameworkcode);
1046 C<$subfield> can be undefined
1050 sub GetAuthValCodeFromField {
1051 my ($field,$subfield,$fwcode) = @_;
1052 my $dbh = C4::Context->dbh;
1053 $fwcode='' unless $fwcode;
1055 if (defined $subfield) {
1056 $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?');
1057 $sth->execute($field,$subfield,$fwcode);
1059 $sth = $dbh->prepare('select authorised_value from marc_tag_structure where tagfield=? and frameworkcode=?');
1060 $sth->execute($field,$fwcode);
1062 my ($authvalcode) = $sth->fetchrow_array;
1063 return $authvalcode;
1066 =head2 GetAuthorisedValues
1068 $authvalues = GetAuthorisedValues([$category], [$selected]);
1070 This function returns all authorised values from the'authorised_value' table in a reference to array of hashrefs.
1072 C<$category> returns authorised values for just one category (optional).
1074 C<$opac> If set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1078 sub GetAuthorisedValues {
1079 my ( $category, $selected, $opac ) = @_;
1080 my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
1082 my $dbh = C4::Context->dbh;
1085 FROM authorised_values
1088 LEFT JOIN authorised_values_branches ON ( id = av_id )
1093 push @where_strings, "category = ?";
1094 push @where_args, $category;
1097 push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
1098 push @where_args, $branch_limit;
1100 if(@where_strings > 0) {
1101 $query .= " WHERE " . join(" AND ", @where_strings);
1103 $query .= " GROUP BY lib";
1104 $query .= ' ORDER BY category, ' . (
1105 $opac ? 'COALESCE(lib_opac, lib)'
1109 my $sth = $dbh->prepare($query);
1111 $sth->execute( @where_args );
1112 while (my $data=$sth->fetchrow_hashref) {
1113 if ( defined $selected and $selected eq $data->{authorised_value} ) {
1114 $data->{selected} = 1;
1117 $data->{selected} = 0;
1120 if ($opac && $data->{lib_opac}) {
1121 $data->{lib} = $data->{lib_opac};
1123 push @results, $data;
1129 =head2 GetAuthorisedValueCategories
1131 $auth_categories = GetAuthorisedValueCategories();
1133 Return an arrayref of all of the available authorised
1138 sub GetAuthorisedValueCategories {
1139 my $dbh = C4::Context->dbh;
1140 my $sth = $dbh->prepare("SELECT DISTINCT category FROM authorised_values ORDER BY category");
1143 while (defined (my $category = $sth->fetchrow_array) ) {
1144 push @results, $category;
1149 =head2 IsAuthorisedValueCategory
1151 $is_auth_val_category = IsAuthorisedValueCategory($category);
1153 Returns whether a given category name is a valid one
1157 sub IsAuthorisedValueCategory {
1158 my $category = shift;
1161 FROM authorised_values
1162 WHERE BINARY category=?
1165 my $sth = C4::Context->dbh->prepare($query);
1166 $sth->execute($category);
1167 $sth->fetchrow ? return 1
1171 =head2 GetAuthorisedValueByCode
1173 $authorised_value = GetAuthorisedValueByCode( $category, $authvalcode, $opac );
1175 Return the lib attribute from authorised_values from the row identified
1176 by the passed category and code
1180 sub GetAuthorisedValueByCode {
1181 my ( $category, $authvalcode, $opac ) = @_;
1183 my $field = $opac ? 'lib_opac' : 'lib';
1184 my $dbh = C4::Context->dbh;
1185 my $sth = $dbh->prepare("SELECT $field FROM authorised_values WHERE category=? AND authorised_value =?");
1186 $sth->execute( $category, $authvalcode );
1187 while ( my $data = $sth->fetchrow_hashref ) {
1188 return $data->{ $field };
1192 =head2 GetKohaAuthorisedValues
1194 Takes $kohafield, $fwcode as parameters.
1196 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1198 Returns hashref of Code => description
1200 Returns undef if no authorised value category is defined for the kohafield.
1204 sub GetKohaAuthorisedValues {
1205 my ($kohafield,$fwcode,$opac) = @_;
1206 $fwcode='' unless $fwcode;
1208 my $dbh = C4::Context->dbh;
1209 my $avcode = GetAuthValCode($kohafield,$fwcode);
1211 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1212 $sth->execute($avcode);
1213 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1214 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1222 =head2 GetKohaAuthorisedValuesFromField
1224 Takes $field, $subfield, $fwcode as parameters.
1226 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1227 $subfield can be undefined
1229 Returns hashref of Code => description
1231 Returns undef if no authorised value category is defined for the given field and subfield
1235 sub GetKohaAuthorisedValuesFromField {
1236 my ($field, $subfield, $fwcode,$opac) = @_;
1237 $fwcode='' unless $fwcode;
1239 my $dbh = C4::Context->dbh;
1240 my $avcode = GetAuthValCodeFromField($field, $subfield, $fwcode);
1242 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1243 $sth->execute($avcode);
1244 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1245 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1255 my $escaped_string = C4::Koha::xml_escape($string);
1257 Convert &, <, >, ', and " in a string to XML entities
1263 return '' unless defined $str;
1264 $str =~ s/&/&/g;
1267 $str =~ s/'/'/g;
1268 $str =~ s/"/"/g;
1272 =head2 GetKohaAuthorisedValueLib
1274 Takes $category, $authorised_value as parameters.
1276 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1278 Returns authorised value description
1282 sub GetKohaAuthorisedValueLib {
1283 my ($category,$authorised_value,$opac) = @_;
1285 my $dbh = C4::Context->dbh;
1286 my $sth = $dbh->prepare("select lib, lib_opac from authorised_values where category=? and authorised_value=?");
1287 $sth->execute($category,$authorised_value);
1288 my $data = $sth->fetchrow_hashref;
1289 $value = ($opac && $$data{'lib_opac'}) ? $$data{'lib_opac'} : $$data{'lib'};
1293 =head2 AddAuthorisedValue
1295 AddAuthorisedValue($category, $authorised_value, $lib, $lib_opac, $imageurl);
1297 Create a new authorised value.
1301 sub AddAuthorisedValue {
1302 my ($category, $authorised_value, $lib, $lib_opac, $imageurl) = @_;
1304 my $dbh = C4::Context->dbh;
1306 INSERT INTO authorised_values (category, authorised_value, lib, lib_opac, imageurl)
1309 my $sth = $dbh->prepare($query);
1310 $sth->execute($category, $authorised_value, $lib, $lib_opac, $imageurl);
1313 =head2 display_marc_indicators
1315 my $display_form = C4::Koha::display_marc_indicators($field);
1317 C<$field> is a MARC::Field object
1319 Generate a display form of the indicators of a variable
1320 MARC field, replacing any blanks with '#'.
1324 sub display_marc_indicators {
1326 my $indicators = '';
1327 if ($field->tag() >= 10) {
1328 $indicators = $field->indicator(1) . $field->indicator(2);
1329 $indicators =~ s/ /#/g;
1334 sub GetNormalizedUPC {
1335 my ($record,$marcflavour) = @_;
1338 if ($marcflavour eq 'UNIMARC') {
1339 @fields = $record->field('072');
1340 foreach my $field (@fields) {
1341 my $upc = _normalize_match_point($field->subfield('a'));
1348 else { # assume marc21 if not unimarc
1349 @fields = $record->field('024');
1350 foreach my $field (@fields) {
1351 my $indicator = $field->indicator(1);
1352 my $upc = _normalize_match_point($field->subfield('a'));
1353 if ($indicator == 1 and $upc ne '') {
1360 # Normalizes and returns the first valid ISBN found in the record
1361 # ISBN13 are converted into ISBN10. This is required to get some book cover images.
1362 sub GetNormalizedISBN {
1363 my ($isbn,$record,$marcflavour) = @_;
1366 # Koha attempts to store multiple ISBNs in biblioitems.isbn, separated by " | "
1367 # anything after " | " should be removed, along with the delimiter
1368 $isbn =~ s/(.*)( \| )(.*)/$1/;
1369 return _isbn_cleanup($isbn);
1371 return unless $record;
1373 if ($marcflavour eq 'UNIMARC') {
1374 @fields = $record->field('010');
1375 foreach my $field (@fields) {
1376 my $isbn = $field->subfield('a');
1378 return _isbn_cleanup($isbn);
1384 else { # assume marc21 if not unimarc
1385 @fields = $record->field('020');
1386 foreach my $field (@fields) {
1387 $isbn = $field->subfield('a');
1389 return _isbn_cleanup($isbn);
1397 sub GetNormalizedEAN {
1398 my ($record,$marcflavour) = @_;
1401 if ($marcflavour eq 'UNIMARC') {
1402 @fields = $record->field('073');
1403 foreach my $field (@fields) {
1404 $ean = _normalize_match_point($field->subfield('a'));
1410 else { # assume marc21 if not unimarc
1411 @fields = $record->field('024');
1412 foreach my $field (@fields) {
1413 my $indicator = $field->indicator(1);
1414 $ean = _normalize_match_point($field->subfield('a'));
1415 if ($indicator == 3 and $ean ne '') {
1421 sub GetNormalizedOCLCNumber {
1422 my ($record,$marcflavour) = @_;
1425 if ($marcflavour eq 'UNIMARC') {
1426 # TODO: add UNIMARC fields
1428 else { # assume marc21 if not unimarc
1429 @fields = $record->field('035');
1430 foreach my $field (@fields) {
1431 $oclc = $field->subfield('a');
1432 if ($oclc =~ /OCoLC/) {
1433 $oclc =~ s/\(OCoLC\)//;
1442 sub GetAuthvalueDropbox {
1443 my ( $authcat, $default ) = @_;
1444 my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
1445 my $dbh = C4::Context->dbh;
1449 FROM authorised_values
1452 LEFT JOIN authorised_values_branches ON ( id = av_id )
1457 $query .= " AND ( branchcode = ? OR branchcode IS NULL )" if $branch_limit;
1458 $query .= " GROUP BY lib ORDER BY category, lib, lib_opac";
1459 my $sth = $dbh->prepare($query);
1460 $sth->execute( $authcat, $branch_limit ? $branch_limit : () );
1463 my $option_list = [];
1464 my @authorised_values = ( q{} );
1465 while (my $av = $sth->fetchrow_hashref) {
1466 push @
{$option_list}, {
1467 value
=> $av->{authorised_value
},
1468 label
=> $av->{lib
},
1469 default => ($default eq $av->{authorised_value
}),
1473 if ( @
{$option_list} ) {
1474 return $option_list;
1480 =head2 GetDailyQuote($opts)
1482 Takes a hashref of options
1484 Currently supported options are:
1486 'id' An exact quote id
1487 'random' Select a random quote
1488 noop When no option is passed in, this sub will return the quote timestamped for the current day
1490 The function returns an anonymous hash following this format:
1493 'source' => 'source-of-quote',
1494 'timestamp' => 'timestamp-value',
1495 'text' => 'text-of-quote',
1501 # This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
1502 # at least for default option
1506 my $dbh = C4
::Context
->dbh;
1511 $query = 'SELECT * FROM quotes WHERE id = ?';
1512 $sth = $dbh->prepare($query);
1513 $sth->execute($opts{'id'});
1514 $quote = $sth->fetchrow_hashref();
1516 elsif ($opts{'random'}) {
1517 # Fall through... we also return a random quote as a catch-all if all else fails
1520 $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp DESC LIMIT 0,1';
1521 $sth = $dbh->prepare($query);
1523 $quote = $sth->fetchrow_hashref();
1525 unless ($quote) { # if there are not matches, choose a random quote
1526 # get a list of all available quote ids
1527 $sth = C4
::Context
->dbh->prepare('SELECT count(*) FROM quotes;');
1529 my $range = ($sth->fetchrow_array)[0];
1530 # chose a random id within that range if there is more than one quote
1531 my $offset = int(rand($range));
1533 $query = 'SELECT * FROM quotes ORDER BY id LIMIT 1 OFFSET ?';
1534 $sth = C4
::Context
->dbh->prepare($query);
1535 # see http://www.perlmonks.org/?node_id=837422 for why
1536 # we're being verbose and using bind_param
1537 $sth->bind_param(1, $offset, SQL_INTEGER
);
1539 $quote = $sth->fetchrow_hashref();
1540 # update the timestamp for that quote
1541 $query = 'UPDATE quotes SET timestamp = ? WHERE id = ?';
1542 $sth = C4
::Context
->dbh->prepare($query);
1544 DateTime
::Format
::MySQL
->format_datetime( dt_from_string
() ),
1551 sub _normalize_match_point
{
1552 my $match_point = shift;
1553 (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
1554 $normalized_match_point =~ s/-//g;
1556 return $normalized_match_point;
1561 return NormalizeISBN
(
1564 format
=> 'ISBN-10',
1570 =head2 NormalizedISBN
1572 my $isbns = NormalizedISBN({
1574 strip_hyphens => [0,1],
1575 format => ['ISBN-10', 'ISBN-13']
1578 Returns an isbn validated by Business::ISBN.
1579 Optionally strips hyphens and/or forces the isbn
1580 to be of the specified format.
1582 If the string cannot be validated as an isbn,
1590 my $string = $params->{isbn
};
1591 my $strip_hyphens = $params->{strip_hyphens
};
1592 my $format = $params->{format
};
1594 return unless $string;
1596 my $isbn = Business
::ISBN
->new($string);
1598 if ( $isbn && $isbn->is_valid() ) {
1600 if ( $format eq 'ISBN-10' ) {
1601 $isbn = $isbn->as_isbn10();
1603 elsif ( $format eq 'ISBN-13' ) {
1604 $isbn = $isbn->as_isbn13();
1607 if ($strip_hyphens) {
1608 $string = $isbn->as_string( [] );
1610 $string = $isbn->as_string();
1617 =head2 GetVariationsOfISBN
1619 my @isbns = GetVariationsOfISBN( $isbn );
1621 Returns a list of varations of the given isbn in
1622 both ISBN-10 and ISBN-13 formats, with and without
1625 In a scalar context, the isbns are returned as a
1626 string delimited by ' | '.
1630 sub GetVariationsOfISBN
{
1633 return unless $isbn;
1637 push( @isbns, NormalizeISBN
({ isbn
=> $isbn }) );
1638 push( @isbns, NormalizeISBN
({ isbn
=> $isbn, format
=> 'ISBN-10' }) );
1639 push( @isbns, NormalizeISBN
({ isbn
=> $isbn, format
=> 'ISBN-13' }) );
1640 push( @isbns, NormalizeISBN
({ isbn
=> $isbn, format
=> 'ISBN-10', strip_hyphens
=> 1 }) );
1641 push( @isbns, NormalizeISBN
({ isbn
=> $isbn, format
=> 'ISBN-13', strip_hyphens
=> 1 }) );
1643 # Strip out any "empty" strings from the array
1644 @isbns = grep { defined($_) && $_ =~ /\S/ } @isbns;
1646 return wantarray ?
@isbns : join( " | ", @isbns );
1649 =head2 GetVariationsOfISBNs
1651 my @isbns = GetVariationsOfISBNs( @isbns );
1653 Returns a list of varations of the given isbns in
1654 both ISBN-10 and ISBN-13 formats, with and without
1657 In a scalar context, the isbns are returned as a
1658 string delimited by ' | '.
1662 sub GetVariationsOfISBNs
{
1665 @isbns = map { GetVariationsOfISBN
( $_ ) } @isbns;
1667 return wantarray ?
@isbns : join( " | ", @isbns );