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
27 use C4
::Branch
; # Can be removed?
29 use Koha
::DateUtils
qw(dt_from_string);
31 use DateTime
::Format
::MySQL
;
33 use autouse
'Data::cselectall_arrayref' => qw(Dumper);
34 use DBI
qw(:sql_types);
35 use vars
qw($VERSION @ISA @EXPORT @EXPORT_OK $DEBUG);
38 $VERSION = 3.07.00.049;
42 &subfield_is_koha_internal_p
43 &GetPrinters &GetPrinter
44 &GetItemTypes &getitemtypeinfo
45 &GetItemTypesCategorized &GetItemTypesByCategory
46 &GetSupportName &GetSupportList
47 &getframeworks &getframeworkinfo
53 &get_notforloan_label_of
56 &getitemtypeimagelocation
58 &GetAuthorisedValueCategories
59 &GetKohaAuthorisedValues
60 &GetKohaAuthorisedValuesFromField
61 &GetKohaAuthorisedValuesMapping
62 &GetKohaAuthorisedValueLib
63 &GetAuthorisedValueByCode
68 &GetNormalizedOCLCNumber
78 @EXPORT_OK = qw( GetDailyQuote );
83 C4::Koha - Perl Module containing convenience functions for Koha scripts
91 Koha.pm provides many functions for Koha scripts.
97 # FIXME.. this should be moved to a MARC-specific module
98 sub subfield_is_koha_internal_p
{
101 # We could match on 'lib' and 'tab' (and 'mandatory', & more to come!)
102 # But real MARC subfields are always single-character
103 # so it really is safer just to check the length
105 return length $subfield != 1;
108 =head2 GetSupportName
110 $itemtypename = &GetSupportName($codestring);
112 Returns a string with the name of the itemtype.
118 return if (! $codestring);
120 my $advanced_search_types = C4
::Context
->preference("AdvancedSearchTypes");
121 if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') {
128 my $sth = C4
::Context
->dbh->prepare($query);
129 $sth->execute($codestring);
130 ($resultstring)=$sth->fetchrow;
131 return $resultstring;
134 C4
::Context
->dbh->prepare(
135 "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
137 $sth->execute( $advanced_search_types, $codestring );
138 my $data = $sth->fetchrow_hashref;
139 return $$data{'lib'};
143 =head2 GetSupportList
145 $itemtypes = &GetSupportList();
147 Returns an array ref containing informations about Support (since itemtype is rather a circulation code when item-level-itypes is used).
149 build a HTML select with the following code :
151 =head3 in PERL SCRIPT
153 my $itemtypes = GetSupportList();
154 $template->param(itemtypeloop => $itemtypes);
158 <select name="itemtype" id="itemtype">
159 <option value=""></option>
160 [% FOREACH itemtypeloo IN itemtypeloop %]
161 [% IF ( itemtypeloo.selected ) %]
162 <option value="[% itemtypeloo.itemtype %]" selected="selected">[% itemtypeloo.description %]</option>
164 <option value="[% itemtypeloo.itemtype %]">[% itemtypeloo.description %]</option>
172 my $advanced_search_types = C4
::Context
->preference("AdvancedSearchTypes");
173 if (!$advanced_search_types or $advanced_search_types =~ /itemtypes/) {
174 return GetItemTypes
( style
=> 'array' );
176 my $advsearchtypes = GetAuthorisedValues
($advanced_search_types);
177 my @results= map {{itemtype
=>$$_{authorised_value
},description
=>$$_{lib
},imageurl
=>$$_{imageurl
}}} @
$advsearchtypes;
183 $itemtypes = &GetItemTypes( style => $style );
185 Returns information about existing itemtypes.
188 style: either 'array' or 'hash', defaults to 'hash'.
189 'array' returns an arrayref,
190 'hash' return a hashref with the itemtype value as the key
192 build a HTML select with the following code :
194 =head3 in PERL SCRIPT
196 my $itemtypes = GetItemTypes;
198 foreach my $thisitemtype (sort keys %$itemtypes) {
199 my $selected = 1 if $thisitemtype eq $itemtype;
200 my %row =(value => $thisitemtype,
201 selected => $selected,
202 description => $itemtypes->{$thisitemtype}->{'description'},
204 push @itemtypesloop, \%row;
206 $template->param(itemtypeloop => \@itemtypesloop);
210 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
211 <select name="itemtype">
212 <option value="">Default</option>
213 <!-- TMPL_LOOP name="itemtypeloop" -->
214 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="description" --></option>
217 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
218 <input type="submit" value="OK" class="button">
225 my $style = defined( $params{'style'} ) ?
$params{'style'} : 'hash';
227 require C4
::Languages
;
228 my $language = C4
::Languages
::getlanguage
();
229 # returns a reference to a hash of references to itemtypes...
230 my $dbh = C4
::Context
->dbh;
234 itemtypes
.description
,
235 itemtypes
.rentalcharge
,
236 itemtypes
.notforloan
,
239 itemtypes
.checkinmsg
,
240 itemtypes
.checkinmsgtype
,
241 itemtypes
.sip_media_type
,
242 itemtypes
.hideinopac
,
243 itemtypes
.searchcategory
,
244 COALESCE
( localization
.translation
, itemtypes
.description
) AS translated_description
246 LEFT JOIN localization ON itemtypes
.itemtype
= localization
.code
247 AND localization
.entity
= 'itemtypes'
248 AND localization
.lang
= ?
251 my $sth = $dbh->prepare($query);
252 $sth->execute( $language );
254 if ( $style eq 'hash' ) {
256 while ( my $IT = $sth->fetchrow_hashref ) {
257 $itemtypes{ $IT->{'itemtype'} } = $IT;
259 return ( \
%itemtypes );
261 return [ sort { lc $a->{translated_description
} cmp lc $b->{translated_description
} } @
{ $sth->fetchall_arrayref( {} ) } ];
265 =head2 GetItemTypesCategorized
267 $categories = GetItemTypesCategorized();
269 Returns a hashref containing search categories.
270 A search category will be put in the hash if at least one of its itemtypes is visible in OPAC.
271 The categories must be part of Authorized Values (ITEMTYPECAT)
275 sub GetItemTypesCategorized
{
276 my $dbh = C4
::Context
->dbh;
277 # Order is important, so that partially hidden (some items are not visible in OPAC) search
278 # categories will be visible. hideinopac=0 must be last.
280 SELECT itemtype
, description
, imageurl
, hideinopac
, 0 as
'iscat' FROM itemtypes WHERE ISNULL
(searchcategory
) or length(searchcategory
) = 0
282 SELECT DISTINCT searchcategory AS
`itemtype`,
283 authorised_values
.lib_opac AS description
,
284 authorised_values
.imageurl AS imageurl
,
285 hideinopac
, 1 as
'iscat'
287 LEFT JOIN authorised_values ON searchcategory
= authorised_value
288 WHERE searchcategory
> '' and hideinopac
=1
290 SELECT DISTINCT searchcategory AS
`itemtype`,
291 authorised_values
.lib_opac AS description
,
292 authorised_values
.imageurl AS imageurl
,
293 hideinopac
, 1 as
'iscat'
295 LEFT JOIN authorised_values ON searchcategory
= authorised_value
296 WHERE searchcategory
> '' and hideinopac
=0
298 return ($dbh->selectall_hashref($query,'itemtype'));
301 =head2 GetItemTypesByCategory
303 @results = GetItemTypesByCategory( $searchcategory );
305 Returns the itemtype code of all itemtypes included in a searchcategory.
309 sub GetItemTypesByCategory
{
313 my $dbh = C4
::Context
->dbh;
314 my $query = qq|SELECT itemtype FROM itemtypes WHERE searchcategory
=?
|;
315 my $tmp=$dbh->selectcol_arrayref($query,undef,$category);
321 $frameworks = &getframework();
323 Returns information about existing frameworks
325 build a HTML select with the following code :
327 =head3 in PERL SCRIPT
329 my $frameworks = getframeworks();
331 foreach my $thisframework (keys %$frameworks) {
332 my $selected = 1 if $thisframework eq $frameworkcode;
334 value => $thisframework,
335 selected => $selected,
336 description => $frameworks->{$thisframework}->{'frameworktext'},
338 push @frameworksloop, \%row;
340 $template->param(frameworkloop => \@frameworksloop);
344 <form action="[% script_name %] method=post>
345 <select name="frameworkcode">
346 <option value="">Default</option>
347 [% FOREACH framework IN frameworkloop %]
348 [% IF ( framework.selected ) %]
349 <option value="[% framework.value %]" selected="selected">[% framework.description %]</option>
351 <option value="[% framework.value %]">[% framework.description %]</option>
355 <input type=text name=searchfield value="[% searchfield %]">
356 <input type="submit" value="OK" class="button">
363 # returns a reference to a hash of references to branches...
365 my $dbh = C4
::Context
->dbh;
366 my $sth = $dbh->prepare("select * from biblio_framework");
368 while ( my $IT = $sth->fetchrow_hashref ) {
369 $itemtypes{ $IT->{'frameworkcode'} } = $IT;
371 return ( \
%itemtypes );
374 =head2 GetFrameworksLoop
376 $frameworks = GetFrameworksLoop( $frameworkcode );
378 Returns the loop suggested on getframework(), but ordered by framework description.
380 build a HTML select with the following code :
382 =head3 in PERL SCRIPT
384 $template->param( frameworkloop => GetFrameworksLoop( $frameworkcode ) );
388 Same as getframework()
390 <form action="[% script_name %] method=post>
391 <select name="frameworkcode">
392 <option value="">Default</option>
393 [% FOREACH framework IN frameworkloop %]
394 [% IF ( framework.selected ) %]
395 <option value="[% framework.value %]" selected="selected">[% framework.description %]</option>
397 <option value="[% framework.value %]">[% framework.description %]</option>
401 <input type=text name=searchfield value="[% searchfield %]">
402 <input type="submit" value="OK" class="button">
407 sub GetFrameworksLoop
{
408 my $frameworkcode = shift;
409 my $frameworks = getframeworks
();
411 foreach my $thisframework (sort { uc($frameworks->{$a}->{'frameworktext'}) cmp uc($frameworks->{$b}->{'frameworktext'}) } keys %$frameworks) {
412 my $selected = ( $thisframework eq $frameworkcode ) ?
1 : undef;
414 value
=> $thisframework,
415 selected
=> $selected,
416 description
=> $frameworks->{$thisframework}->{'frameworktext'},
418 push @frameworkloop, \
%row;
420 return \
@frameworkloop;
423 =head2 getframeworkinfo
425 $frameworkinfo = &getframeworkinfo($frameworkcode);
427 Returns information about an frameworkcode.
431 sub getframeworkinfo
{
432 my ($frameworkcode) = @_;
433 my $dbh = C4
::Context
->dbh;
435 $dbh->prepare("select * from biblio_framework where frameworkcode=?");
436 $sth->execute($frameworkcode);
437 my $res = $sth->fetchrow_hashref;
441 =head2 getitemtypeinfo
443 $itemtype = &getitemtypeinfo($itemtype, [$interface]);
445 Returns information about an itemtype. The optional $interface argument
446 sets which interface ('opac' or 'intranet') to return the imageurl for.
447 Defaults to intranet.
451 sub getitemtypeinfo
{
452 my ($itemtype, $interface) = @_;
453 my $dbh = C4
::Context
->dbh;
454 require C4
::Languages
;
455 my $language = C4
::Languages
::getlanguage
();
456 my $it = $dbh->selectrow_hashref(q
|
459 itemtypes
.description
,
460 itemtypes
.rentalcharge
,
461 itemtypes
.notforloan
,
464 itemtypes
.checkinmsg
,
465 itemtypes
.checkinmsgtype
,
466 itemtypes
.sip_media_type
,
467 COALESCE
( localization
.translation
, itemtypes
.description
) AS translated_description
469 LEFT JOIN localization ON itemtypes
.itemtype
= localization
.code
470 AND localization
.entity
= 'itemtypes'
471 AND localization
.lang
= ?
472 WHERE itemtypes
.itemtype
= ?
473 |, undef, $language, $itemtype );
475 $it->{imageurl
} = getitemtypeimagelocation
( ( ( defined $interface && $interface eq 'opac' ) ?
'opac' : 'intranet' ), $it->{imageurl
} );
480 =head2 getitemtypeimagedir
482 my $directory = getitemtypeimagedir( 'opac' );
484 pass in 'opac' or 'intranet'. Defaults to 'opac'.
486 returns the full path to the appropriate directory containing images.
490 sub getitemtypeimagedir
{
491 my $src = shift || 'opac';
492 if ($src eq 'intranet') {
493 return C4
::Context
->config('intrahtdocs') . '/' .C4
::Context
->preference('template') . '/img/itemtypeimg';
495 return C4
::Context
->config('opachtdocs') . '/' . C4
::Context
->preference('opacthemes') . '/itemtypeimg';
499 sub getitemtypeimagesrc
{
500 my $src = shift || 'opac';
501 if ($src eq 'intranet') {
502 return '/intranet-tmpl' . '/' . C4
::Context
->preference('template') . '/img/itemtypeimg';
504 return '/opac-tmpl' . '/' . C4
::Context
->preference('opacthemes') . '/itemtypeimg';
508 sub getitemtypeimagelocation
{
509 my ( $src, $image ) = @_;
511 return '' if ( !$image );
514 my $scheme = ( URI
::Split
::uri_split
( $image ) )[0];
516 return $image if ( $scheme );
518 return getitemtypeimagesrc
( $src ) . '/' . $image;
521 =head3 _getImagesFromDirectory
523 Find all of the image files in a directory in the filesystem
525 parameters: a directory name
527 returns: a list of images in that directory.
529 Notes: this does not traverse into subdirectories. See
530 _getSubdirectoryNames for help with that.
531 Images are assumed to be files with .gif or .png file extensions.
532 The image names returned do not have the directory name on them.
536 sub _getImagesFromDirectory
{
537 my $directoryname = shift;
538 return unless defined $directoryname;
539 return unless -d
$directoryname;
541 if ( opendir ( my $dh, $directoryname ) ) {
542 my @images = grep { /\.(gif|png)$/i } readdir( $dh );
544 @images = sort(@images);
547 warn "unable to opendir $directoryname: $!";
552 =head3 _getSubdirectoryNames
554 Find all of the directories in a directory in the filesystem
556 parameters: a directory name
558 returns: a list of subdirectories in that directory.
560 Notes: this does not traverse into subdirectories. Only the first
561 level of subdirectories are returned.
562 The directory names returned don't have the parent directory name on them.
566 sub _getSubdirectoryNames
{
567 my $directoryname = shift;
568 return unless defined $directoryname;
569 return unless -d
$directoryname;
571 if ( opendir ( my $dh, $directoryname ) ) {
572 my @directories = grep { -d File
::Spec
->catfile( $directoryname, $_ ) && ! ( /^\./ ) } readdir( $dh );
576 warn "unable to opendir $directoryname: $!";
583 returns: a listref of hashrefs. Each hash represents another collection of images.
585 { imagesetname => 'npl', # the name of the image set (npl is the original one)
586 images => listref of image hashrefs
589 each image is represented by a hashref like this:
591 { KohaImage => 'npl/image.gif',
592 StaffImageUrl => '/intranet-tmpl/prog/img/itemtypeimg/npl/image.gif',
593 OpacImageURL => '/opac-tmpl/prog/itemtypeimg/npl/image.gif'
594 checked => 0 or 1: was this the image passed to this method?
595 Note: I'd like to remove this somehow.
602 my $checked = $params{'checked'} || '';
604 my $paths = { staff
=> { filesystem
=> getitemtypeimagedir
('intranet'),
605 url
=> getitemtypeimagesrc
('intranet'),
607 opac
=> { filesystem
=> getitemtypeimagedir
('opac'),
608 url
=> getitemtypeimagesrc
('opac'),
612 my @imagesets = (); # list of hasrefs of image set data to pass to template
613 my @subdirectories = _getSubdirectoryNames
( $paths->{'staff'}{'filesystem'} );
614 foreach my $imagesubdir ( @subdirectories ) {
615 warn $imagesubdir if $DEBUG;
616 my @imagelist = (); # hashrefs of image info
617 my @imagenames = _getImagesFromDirectory
( File
::Spec
->catfile( $paths->{'staff'}{'filesystem'}, $imagesubdir ) );
618 my $imagesetactive = 0;
619 foreach my $thisimage ( @imagenames ) {
621 { KohaImage
=> "$imagesubdir/$thisimage",
622 StaffImageUrl
=> join( '/', $paths->{'staff'}{'url'}, $imagesubdir, $thisimage ),
623 OpacImageUrl
=> join( '/', $paths->{'opac'}{'url'}, $imagesubdir, $thisimage ),
624 checked
=> "$imagesubdir/$thisimage" eq $checked ?
1 : 0,
627 $imagesetactive = 1 if "$imagesubdir/$thisimage" eq $checked;
629 push @imagesets, { imagesetname
=> $imagesubdir,
630 imagesetactive
=> $imagesetactive,
631 images
=> \
@imagelist };
639 $printers = &GetPrinters();
640 @queues = keys %$printers;
642 Returns information about existing printer queues.
644 C<$printers> is a reference-to-hash whose keys are the print queues
645 defined in the printers table of the Koha database. The values are
646 references-to-hash, whose keys are the fields in the printers table.
652 my $dbh = C4
::Context
->dbh;
653 my $sth = $dbh->prepare("select * from printers");
655 while ( my $printer = $sth->fetchrow_hashref ) {
656 $printers{ $printer->{'printqueue'} } = $printer;
658 return ( \
%printers );
663 $printer = GetPrinter( $query, $printers );
668 my ( $query, $printers ) = @_; # get printer for this query from printers
669 my $printer = $query->param('printer');
670 my %cookie = $query->cookie('userenv');
671 ($printer) || ( $printer = $cookie{'printer'} ) || ( $printer = '' );
672 ( $printers->{$printer} ) || ( $printer = ( keys %$printers )[0] );
678 Returns the number of pages to display in a pagination bar, given the number
679 of items and the number of items per page.
684 my ( $nb_items, $nb_items_per_page ) = @_;
686 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
691 (@themes) = &getallthemes('opac');
692 (@themes) = &getallthemes('intranet');
694 Returns an array of all available themes.
702 if ( $type eq 'intranet' ) {
703 $htdocs = C4
::Context
->config('intrahtdocs');
706 $htdocs = C4
::Context
->config('opachtdocs');
708 opendir D
, "$htdocs";
709 my @dirlist = readdir D
;
710 foreach my $directory (@dirlist) {
711 next if $directory eq 'lib';
712 -d
"$htdocs/$directory/en" and push @themes, $directory;
719 if ( C4
::Context
->preference("marcflavour") eq "UNIMARC" ) {
724 tags
=> [ qw
/ 600ab 601ab 602a 604at 605a 606ax 610a / ],
730 tags
=> [ qw
/ 607a / ],
736 tags
=> [ qw
/ 500a 501a 503a / ],
742 tags
=> [ qw
/ 700ab 701ab 702ab / ],
743 sep
=> C4
::Context
->preference("UNIMARCAuthorsFacetsSeparator"),
748 tags
=> [ qw
/ 225a / ],
754 tags
=> [ qw
/ 995e / ],
758 unless ( Koha
::Libraries
->search->count == 1 )
760 my $DisplayLibraryFacets = C4
::Context
->preference('DisplayLibraryFacets');
761 if ( $DisplayLibraryFacets eq 'both'
762 || $DisplayLibraryFacets eq 'holding' )
767 idx
=> 'holdingbranch',
768 label
=> 'HoldingLibrary',
769 tags
=> [qw
/ 995c /],
774 if ( $DisplayLibraryFacets eq 'both'
775 || $DisplayLibraryFacets eq 'home' )
781 label
=> 'HomeLibrary',
782 tags
=> [qw
/ 995b /],
793 tags
=> [ qw
/ 650a / ],
798 # label => 'People and Organizations',
799 # tags => [ qw/ 600a 610a 611a / ],
805 tags
=> [ qw
/ 651a / ],
811 tags
=> [ qw
/ 630a / ],
817 tags
=> [ qw
/ 100a 110a 700a / ],
823 tags
=> [ qw
/ 440a 490a / ],
828 label
=> 'ItemTypes',
829 tags
=> [ qw
/ 952y 942c / ],
835 tags
=> [ qw
/ 952c / ],
839 unless ( Koha
::Libraries
->search->count == 1 )
841 my $DisplayLibraryFacets = C4
::Context
->preference('DisplayLibraryFacets');
842 if ( $DisplayLibraryFacets eq 'both'
843 || $DisplayLibraryFacets eq 'holding' )
848 idx
=> 'holdingbranch',
849 label
=> 'HoldingLibrary',
850 tags
=> [qw
/ 952b /],
855 if ( $DisplayLibraryFacets eq 'both'
856 || $DisplayLibraryFacets eq 'home' )
862 label
=> 'HomeLibrary',
863 tags
=> [qw
/ 952a /],
874 Return a href where a key is associated to a href. You give a query,
875 the name of the key among the fields returned by the query. If you
876 also give as third argument the name of the value, the function
877 returns a href of scalar. The optional 4th argument is an arrayref of
878 items passed to the C<execute()> call. It is designed to bind
879 parameters to any placeholders in your SQL.
888 # generic href of any information on the item, href of href.
889 my $iteminfos_of = get_infos_of($query, 'itemnumber');
890 print $iteminfos_of->{$itemnumber}{barcode};
892 # specific information, href of scalar
893 my $barcode_of_item = get_infos_of($query, 'itemnumber', 'barcode');
894 print $barcode_of_item->{$itemnumber};
899 my ( $query, $key_name, $value_name, $bind_params ) = @_;
901 my $dbh = C4
::Context
->dbh;
903 my $sth = $dbh->prepare($query);
904 $sth->execute( @
$bind_params );
907 while ( my $row = $sth->fetchrow_hashref ) {
908 if ( defined $value_name ) {
909 $infos_of{ $row->{$key_name} } = $row->{$value_name};
912 $infos_of{ $row->{$key_name} } = $row;
920 =head2 get_notforloan_label_of
922 my $notforloan_label_of = get_notforloan_label_of();
924 Each authorised value of notforloan (information available in items and
925 itemtypes) is link to a single label.
927 Returns a href where keys are authorised values and values are corresponding
930 foreach my $authorised_value (keys %{$notforloan_label_of}) {
932 "authorised_value: %s => %s\n",
934 $notforloan_label_of->{$authorised_value}
940 # FIXME - why not use GetAuthorisedValues ??
942 sub get_notforloan_label_of
{
943 my $dbh = C4
::Context
->dbh;
946 SELECT authorised_value
947 FROM marc_subfield_structure
948 WHERE kohafield = \'items.notforloan\'
951 my $sth = $dbh->prepare($query);
953 my ($statuscode) = $sth->fetchrow_array();
958 FROM authorised_values
961 $sth = $dbh->prepare($query);
962 $sth->execute($statuscode);
963 my %notforloan_label_of;
964 while ( my $row = $sth->fetchrow_hashref ) {
965 $notforloan_label_of{ $row->{authorised_value
} } = $row->{lib
};
969 return \
%notforloan_label_of;
972 =head2 GetAuthValCode
974 $authvalcode = GetAuthValCode($kohafield,$frameworkcode);
979 my ($kohafield,$fwcode) = @_;
980 my $dbh = C4
::Context
->dbh;
981 $fwcode='' unless $fwcode;
982 my $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield=? and frameworkcode=?');
983 $sth->execute($kohafield,$fwcode);
984 my ($authvalcode) = $sth->fetchrow_array;
988 =head2 GetAuthValCodeFromField
990 $authvalcode = GetAuthValCodeFromField($field,$subfield,$frameworkcode);
992 C<$subfield> can be undefined
996 sub GetAuthValCodeFromField
{
997 my ($field,$subfield,$fwcode) = @_;
998 my $dbh = C4
::Context
->dbh;
999 $fwcode='' unless $fwcode;
1001 if (defined $subfield) {
1002 $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?');
1003 $sth->execute($field,$subfield,$fwcode);
1005 $sth = $dbh->prepare('select authorised_value from marc_tag_structure where tagfield=? and frameworkcode=?');
1006 $sth->execute($field,$fwcode);
1008 my ($authvalcode) = $sth->fetchrow_array;
1009 return $authvalcode;
1012 =head2 GetAuthorisedValues
1014 $authvalues = GetAuthorisedValues([$category], [$selected]);
1016 This function returns all authorised values from the'authorised_value' table in a reference to array of hashrefs.
1018 C<$category> returns authorised values for just one category (optional).
1020 C<$selected> adds a "selected => 1" entry to the hash if the
1021 authorised_value matches it. B<NOTE:> this feature should be considered
1022 deprecated as it may be removed in the future.
1024 C<$opac> If set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1028 sub GetAuthorisedValues
{
1029 my ( $category, $selected, $opac ) = @_;
1031 # TODO: the "selected" feature should be replaced by a utility function
1032 # somewhere else, it doesn't belong in here. For starters it makes
1033 # caching much more complicated. Or just let the UI logic handle it, it's
1036 # Is this cached already?
1037 $opac = $opac ?
1 : 0; # normalise to be safe
1039 C4
::Context
->userenv ? C4
::Context
->userenv->{"branch"} : "";
1040 my $selected_key = defined($selected) ?
$selected : '';
1042 "AuthorisedValues-$category-$selected_key-$opac-$branch_limit";
1043 my $cache = Koha
::Cache
->get_instance();
1044 my $result = $cache->get_from_cache($cache_key);
1045 return $result if $result;
1048 my $dbh = C4
::Context
->dbh;
1051 FROM authorised_values
1054 LEFT JOIN authorised_values_branches ON
( id
= av_id
)
1059 push @where_strings, "category = ?";
1060 push @where_args, $category;
1063 push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
1064 push @where_args, $branch_limit;
1066 if(@where_strings > 0) {
1067 $query .= " WHERE " . join(" AND ", @where_strings);
1069 $query .= " GROUP BY lib";
1070 $query .= ' ORDER BY category, ' . (
1071 $opac ?
'COALESCE(lib_opac, lib)'
1075 my $sth = $dbh->prepare($query);
1077 $sth->execute( @where_args );
1078 while (my $data=$sth->fetchrow_hashref) {
1079 if ( defined $selected and $selected eq $data->{authorised_value
} ) {
1080 $data->{selected
} = 1;
1083 $data->{selected
} = 0;
1086 if ($opac && $data->{lib_opac
}) {
1087 $data->{lib
} = $data->{lib_opac
};
1089 push @results, $data;
1093 # We can't cache for long because of that "selected" thing which
1094 # makes it impossible to clear the cache without iterating through every
1095 # value, which sucks. This'll cover this request, and not a whole lot more.
1096 $cache->set_in_cache( $cache_key, \
@results, { deepcopy
=> 1, expiry
=> 5 } );
1100 =head2 GetAuthorisedValueCategories
1102 $auth_categories = GetAuthorisedValueCategories();
1104 Return an arrayref of all of the available authorised
1109 sub GetAuthorisedValueCategories
{
1110 my $dbh = C4
::Context
->dbh;
1111 my $sth = $dbh->prepare("SELECT DISTINCT category FROM authorised_values ORDER BY category");
1114 while (defined (my $category = $sth->fetchrow_array) ) {
1115 push @results, $category;
1120 =head2 GetAuthorisedValueByCode
1122 $authorised_value = GetAuthorisedValueByCode( $category, $authvalcode, $opac );
1124 Return the lib attribute from authorised_values from the row identified
1125 by the passed category and code
1129 sub GetAuthorisedValueByCode
{
1130 my ( $category, $authvalcode, $opac ) = @_;
1132 my $field = $opac ?
'lib_opac' : 'lib';
1133 my $dbh = C4
::Context
->dbh;
1134 my $sth = $dbh->prepare("SELECT $field FROM authorised_values WHERE category=? AND authorised_value =?");
1135 $sth->execute( $category, $authvalcode );
1136 while ( my $data = $sth->fetchrow_hashref ) {
1137 return $data->{ $field };
1141 =head2 GetKohaAuthorisedValues
1143 Takes $kohafield, $fwcode as parameters.
1145 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1147 Returns hashref of Code => description
1149 Returns undef if no authorised value category is defined for the kohafield.
1153 sub GetKohaAuthorisedValues
{
1154 my ($kohafield,$fwcode,$opac) = @_;
1155 $fwcode='' unless $fwcode;
1157 my $dbh = C4
::Context
->dbh;
1158 my $avcode = GetAuthValCode
($kohafield,$fwcode);
1160 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1161 $sth->execute($avcode);
1162 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1163 $values{$val} = ($opac && $lib_opac) ?
$lib_opac : $lib;
1171 =head2 GetKohaAuthorisedValuesFromField
1173 Takes $field, $subfield, $fwcode as parameters.
1175 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1176 $subfield can be undefined
1178 Returns hashref of Code => description
1180 Returns undef if no authorised value category is defined for the given field and subfield
1184 sub GetKohaAuthorisedValuesFromField
{
1185 my ($field, $subfield, $fwcode,$opac) = @_;
1186 $fwcode='' unless $fwcode;
1188 my $dbh = C4
::Context
->dbh;
1189 my $avcode = GetAuthValCodeFromField
($field, $subfield, $fwcode);
1191 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1192 $sth->execute($avcode);
1193 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1194 $values{$val} = ($opac && $lib_opac) ?
$lib_opac : $lib;
1202 =head2 GetKohaAuthorisedValuesMapping
1204 Takes a hash as a parameter. The interface key indicates the
1205 description to use in the mapping.
1208 "{kohafield},{frameworkcode},{authorised_value}" => "{description}"
1209 for all the kohafields, frameworkcodes, and authorised values.
1211 Returns undef if nothing is found.
1215 sub GetKohaAuthorisedValuesMapping
{
1216 my ($parameter) = @_;
1217 my $interface = $parameter->{'interface'} // '';
1219 my $query_mapping = q{
1220 SELECT TA.kohafield,TA.authorised_value AS category,
1221 TA.frameworkcode,TB.authorised_value,
1222 IF(TB.lib_opac>'',TB.lib_opac,TB.lib) AS OPAC,
1223 TB.lib AS Intranet,TB.lib_opac
1224 FROM marc_subfield_structure AS TA JOIN
1225 authorised_values as TB ON
1226 TA.authorised_value=TB.category
1227 WHERE TA.kohafield>'' AND TA.authorised_value>'';
1229 my $dbh = C4
::Context
->dbh;
1230 my $sth = $dbh->prepare($query_mapping);
1233 if ($interface eq 'opac') {
1234 while (my $row = $sth->fetchrow_hashref) {
1235 $avmapping->{$row->{kohafield
}.",".$row->{frameworkcode
}.",".$row->{authorised_value
}} = $row->{OPAC
};
1239 while (my $row = $sth->fetchrow_hashref) {
1240 $avmapping->{$row->{kohafield
}.",".$row->{frameworkcode
}.",".$row->{authorised_value
}} = $row->{Intranet
};
1248 my $escaped_string = C4::Koha::xml_escape($string);
1250 Convert &, <, >, ', and " in a string to XML entities
1256 return '' unless defined $str;
1257 $str =~ s/&/&/g;
1260 $str =~ s/'/'/g;
1261 $str =~ s/"/"/g;
1265 =head2 GetKohaAuthorisedValueLib
1267 Takes $category, $authorised_value as parameters.
1269 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1271 Returns authorised value description
1275 sub GetKohaAuthorisedValueLib
{
1276 my ($category,$authorised_value,$opac) = @_;
1278 my $dbh = C4
::Context
->dbh;
1279 my $sth = $dbh->prepare("select lib, lib_opac from authorised_values where category=? and authorised_value=?");
1280 $sth->execute($category,$authorised_value);
1281 my $data = $sth->fetchrow_hashref;
1282 $value = ($opac && $$data{'lib_opac'}) ?
$$data{'lib_opac'} : $$data{'lib'};
1286 =head2 display_marc_indicators
1288 my $display_form = C4::Koha::display_marc_indicators($field);
1290 C<$field> is a MARC::Field object
1292 Generate a display form of the indicators of a variable
1293 MARC field, replacing any blanks with '#'.
1297 sub display_marc_indicators
{
1299 my $indicators = '';
1300 if ($field && $field->tag() >= 10) {
1301 $indicators = $field->indicator(1) . $field->indicator(2);
1302 $indicators =~ s/ /#/g;
1307 sub GetNormalizedUPC
{
1308 my ($marcrecord,$marcflavour) = @_;
1310 return unless $marcrecord;
1311 if ($marcflavour eq 'UNIMARC') {
1312 my @fields = $marcrecord->field('072');
1313 foreach my $field (@fields) {
1314 my $upc = _normalize_match_point
($field->subfield('a'));
1321 else { # assume marc21 if not unimarc
1322 my @fields = $marcrecord->field('024');
1323 foreach my $field (@fields) {
1324 my $indicator = $field->indicator(1);
1325 my $upc = _normalize_match_point
($field->subfield('a'));
1326 if ($upc && $indicator == 1 ) {
1333 # Normalizes and returns the first valid ISBN found in the record
1334 # ISBN13 are converted into ISBN10. This is required to get some book cover images.
1335 sub GetNormalizedISBN
{
1336 my ($isbn,$marcrecord,$marcflavour) = @_;
1338 # Koha attempts to store multiple ISBNs in biblioitems.isbn, separated by " | "
1339 # anything after " | " should be removed, along with the delimiter
1340 ($isbn) = split(/\|/, $isbn );
1341 return _isbn_cleanup
($isbn);
1344 return unless $marcrecord;
1346 if ($marcflavour eq 'UNIMARC') {
1347 my @fields = $marcrecord->field('010');
1348 foreach my $field (@fields) {
1349 my $isbn = $field->subfield('a');
1351 return _isbn_cleanup
($isbn);
1355 else { # assume marc21 if not unimarc
1356 my @fields = $marcrecord->field('020');
1357 foreach my $field (@fields) {
1358 $isbn = $field->subfield('a');
1360 return _isbn_cleanup
($isbn);
1366 sub GetNormalizedEAN
{
1367 my ($marcrecord,$marcflavour) = @_;
1369 return unless $marcrecord;
1371 if ($marcflavour eq 'UNIMARC') {
1372 my @fields = $marcrecord->field('073');
1373 foreach my $field (@fields) {
1374 my $ean = _normalize_match_point
($field->subfield('a'));
1380 else { # assume marc21 if not unimarc
1381 my @fields = $marcrecord->field('024');
1382 foreach my $field (@fields) {
1383 my $indicator = $field->indicator(1);
1384 my $ean = _normalize_match_point
($field->subfield('a'));
1385 if ( $ean && $indicator == 3 ) {
1392 sub GetNormalizedOCLCNumber
{
1393 my ($marcrecord,$marcflavour) = @_;
1394 return unless $marcrecord;
1396 if ($marcflavour ne 'UNIMARC' ) {
1397 my @fields = $marcrecord->field('035');
1398 foreach my $field (@fields) {
1399 my $oclc = $field->subfield('a');
1400 if ($oclc =~ /OCoLC/) {
1401 $oclc =~ s/\(OCoLC\)//;
1411 sub GetAuthvalueDropbox
{
1412 my ( $authcat, $default ) = @_;
1413 my $branch_limit = C4
::Context
->userenv ? C4
::Context
->userenv->{"branch"} : "";
1414 my $dbh = C4
::Context
->dbh;
1418 FROM authorised_values
1421 LEFT JOIN authorised_values_branches ON
( id
= av_id
)
1426 $query .= " AND ( branchcode = ? OR branchcode IS NULL )" if $branch_limit;
1427 $query .= " GROUP BY lib ORDER BY category, lib, lib_opac";
1428 my $sth = $dbh->prepare($query);
1429 $sth->execute( $authcat, $branch_limit ?
$branch_limit : () );
1432 my $option_list = [];
1433 my @authorised_values = ( q{} );
1434 while (my $av = $sth->fetchrow_hashref) {
1435 push @
{$option_list}, {
1436 value
=> $av->{authorised_value
},
1437 label
=> $av->{lib
},
1438 default => ($default eq $av->{authorised_value
}),
1442 if ( @
{$option_list} ) {
1443 return $option_list;
1449 =head2 GetDailyQuote($opts)
1451 Takes a hashref of options
1453 Currently supported options are:
1455 'id' An exact quote id
1456 'random' Select a random quote
1457 noop When no option is passed in, this sub will return the quote timestamped for the current day
1459 The function returns an anonymous hash following this format:
1462 'source' => 'source-of-quote',
1463 'timestamp' => 'timestamp-value',
1464 'text' => 'text-of-quote',
1470 # This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
1471 # at least for default option
1475 my $dbh = C4
::Context
->dbh;
1480 $query = 'SELECT * FROM quotes WHERE id = ?';
1481 $sth = $dbh->prepare($query);
1482 $sth->execute($opts{'id'});
1483 $quote = $sth->fetchrow_hashref();
1485 elsif ($opts{'random'}) {
1486 # Fall through... we also return a random quote as a catch-all if all else fails
1489 $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp DESC LIMIT 0,1';
1490 $sth = $dbh->prepare($query);
1492 $quote = $sth->fetchrow_hashref();
1494 unless ($quote) { # if there are not matches, choose a random quote
1495 # get a list of all available quote ids
1496 $sth = C4
::Context
->dbh->prepare('SELECT count(*) FROM quotes;');
1498 my $range = ($sth->fetchrow_array)[0];
1499 # chose a random id within that range if there is more than one quote
1500 my $offset = int(rand($range));
1502 $query = 'SELECT * FROM quotes ORDER BY id LIMIT 1 OFFSET ?';
1503 $sth = C4
::Context
->dbh->prepare($query);
1504 # see http://www.perlmonks.org/?node_id=837422 for why
1505 # we're being verbose and using bind_param
1506 $sth->bind_param(1, $offset, SQL_INTEGER
);
1508 $quote = $sth->fetchrow_hashref();
1509 # update the timestamp for that quote
1510 $query = 'UPDATE quotes SET timestamp = ? WHERE id = ?';
1511 $sth = C4
::Context
->dbh->prepare($query);
1513 DateTime
::Format
::MySQL
->format_datetime( dt_from_string
() ),
1520 sub _normalize_match_point
{
1521 my $match_point = shift;
1522 (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
1523 $normalized_match_point =~ s/-//g;
1525 return $normalized_match_point;
1530 return NormalizeISBN
(
1533 format
=> 'ISBN-10',
1539 =head2 NormalizedISBN
1541 my $isbns = NormalizedISBN({
1543 strip_hyphens => [0,1],
1544 format => ['ISBN-10', 'ISBN-13']
1547 Returns an isbn validated by Business::ISBN.
1548 Optionally strips hyphens and/or forces the isbn
1549 to be of the specified format.
1551 If the string cannot be validated as an isbn,
1559 my $string = $params->{isbn
};
1560 my $strip_hyphens = $params->{strip_hyphens
};
1561 my $format = $params->{format
};
1563 return unless $string;
1565 my $isbn = Business
::ISBN
->new($string);
1567 if ( $isbn && $isbn->is_valid() ) {
1569 if ( $format eq 'ISBN-10' ) {
1570 $isbn = $isbn->as_isbn10();
1572 elsif ( $format eq 'ISBN-13' ) {
1573 $isbn = $isbn->as_isbn13();
1575 return unless $isbn;
1577 if ($strip_hyphens) {
1578 $string = $isbn->as_string( [] );
1580 $string = $isbn->as_string();
1587 =head2 GetVariationsOfISBN
1589 my @isbns = GetVariationsOfISBN( $isbn );
1591 Returns a list of variations of the given isbn in
1592 both ISBN-10 and ISBN-13 formats, with and without
1595 In a scalar context, the isbns are returned as a
1596 string delimited by ' | '.
1600 sub GetVariationsOfISBN
{
1603 return unless $isbn;
1607 push( @isbns, NormalizeISBN
({ isbn
=> $isbn }) );
1608 push( @isbns, NormalizeISBN
({ isbn
=> $isbn, format
=> 'ISBN-10' }) );
1609 push( @isbns, NormalizeISBN
({ isbn
=> $isbn, format
=> 'ISBN-13' }) );
1610 push( @isbns, NormalizeISBN
({ isbn
=> $isbn, format
=> 'ISBN-10', strip_hyphens
=> 1 }) );
1611 push( @isbns, NormalizeISBN
({ isbn
=> $isbn, format
=> 'ISBN-13', strip_hyphens
=> 1 }) );
1613 # Strip out any "empty" strings from the array
1614 @isbns = grep { defined($_) && $_ =~ /\S/ } @isbns;
1616 return wantarray ?
@isbns : join( " | ", @isbns );
1619 =head2 GetVariationsOfISBNs
1621 my @isbns = GetVariationsOfISBNs( @isbns );
1623 Returns a list of variations of the given isbns in
1624 both ISBN-10 and ISBN-13 formats, with and without
1627 In a scalar context, the isbns are returned as a
1628 string delimited by ' | '.
1632 sub GetVariationsOfISBNs
{
1635 @isbns = map { GetVariationsOfISBN
( $_ ) } @isbns;
1637 return wantarray ?
@isbns : join( " | ", @isbns );
1640 =head2 IsKohaFieldLinked
1642 my $is_linked = IsKohaFieldLinked({
1643 kohafield => $kohafield,
1644 frameworkcode => $frameworkcode,
1647 Return 1 if the field is linked
1651 sub IsKohaFieldLinked
{
1652 my ( $params ) = @_;
1653 my $kohafield = $params->{kohafield
};
1654 my $frameworkcode = $params->{frameworkcode
} || '';
1655 my $dbh = C4
::Context
->dbh;
1656 my $is_linked = $dbh->selectcol_arrayref( q
|
1658 FROM marc_subfield_structure
1659 WHERE frameworkcode
= ?
1661 |,{}, $frameworkcode, $kohafield );
1662 return $is_linked->[0];