Bug 8753 - Add forgot password link to OPAC
[koha.git] / C4 / Koha.pm
blob7171f1673f7f24943ca33408aa14fdd8da011a6e
1 package C4::Koha;
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>.
23 use strict;
24 #use warnings; FIXME - Bug 2505
26 use C4::Context;
27 use C4::Branch; # Can be removed?
28 use Koha::Cache;
29 use Koha::DateUtils qw(dt_from_string);
30 use Koha::Libraries;
31 use DateTime::Format::MySQL;
32 use Business::ISBN;
33 use autouse 'Data::cselectall_arrayref' => qw(Dumper);
34 use DBI qw(:sql_types);
35 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $DEBUG);
37 BEGIN {
38 $VERSION = 3.07.00.049;
39 require Exporter;
40 @ISA = qw(Exporter);
41 @EXPORT = qw(
42 &slashifyDate
43 &subfield_is_koha_internal_p
44 &GetPrinters &GetPrinter
45 &GetItemTypes &getitemtypeinfo
46 &GetItemTypesCategorized &GetItemTypesByCategory
47 &GetSupportName &GetSupportList
48 &get_itemtypeinfos_of
49 &getframeworks &getframeworkinfo
50 &GetFrameworksLoop
51 &getallthemes
52 &getFacets
53 &displayServers
54 &getnbpages
55 &get_infos_of
56 &get_notforloan_label_of
57 &getitemtypeimagedir
58 &getitemtypeimagesrc
59 &getitemtypeimagelocation
60 &GetAuthorisedValues
61 &GetAuthorisedValueCategories
62 &IsAuthorisedValueCategory
63 &GetKohaAuthorisedValues
64 &GetKohaAuthorisedValuesFromField
65 &GetKohaAuthorisedValuesMapping
66 &GetKohaAuthorisedValueLib
67 &GetAuthorisedValueByCode
68 &GetKohaImageurlFromAuthorisedValues
69 &GetAuthValCode
70 &AddAuthorisedValue
71 &GetNormalizedUPC
72 &GetNormalizedISBN
73 &GetNormalizedEAN
74 &GetNormalizedOCLCNumber
75 &xml_escape
77 &GetVariationsOfISBN
78 &GetVariationsOfISBNs
79 &NormalizeISBN
81 $DEBUG
83 $DEBUG = 0;
84 @EXPORT_OK = qw( GetDailyQuote );
87 =head1 NAME
89 C4::Koha - Perl Module containing convenience functions for Koha scripts
91 =head1 SYNOPSIS
93 use C4::Koha;
95 =head1 DESCRIPTION
97 Koha.pm provides many functions for Koha scripts.
99 =head1 FUNCTIONS
101 =cut
103 =head2 slashifyDate
105 $slash_date = &slashifyDate($dash_date);
107 Takes a string of the form "DD-MM-YYYY" (or anything separated by
108 dashes), converts it to the form "YYYY/MM/DD", and returns the result.
110 =cut
112 sub slashifyDate {
114 # accepts a date of the form xx-xx-xx[xx] and returns it in the
115 # form xx/xx/xx[xx]
116 my @dateOut = split( '-', shift );
117 return ("$dateOut[2]/$dateOut[1]/$dateOut[0]");
120 # FIXME.. this should be moved to a MARC-specific module
121 sub subfield_is_koha_internal_p {
122 my ($subfield) = @_;
124 # We could match on 'lib' and 'tab' (and 'mandatory', & more to come!)
125 # But real MARC subfields are always single-character
126 # so it really is safer just to check the length
128 return length $subfield != 1;
131 =head2 GetSupportName
133 $itemtypename = &GetSupportName($codestring);
135 Returns a string with the name of the itemtype.
137 =cut
139 sub GetSupportName{
140 my ($codestring)=@_;
141 return if (! $codestring);
142 my $resultstring;
143 my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
144 if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') {
145 my $query = qq|
146 SELECT description
147 FROM itemtypes
148 WHERE itemtype=?
149 order by description
151 my $sth = C4::Context->dbh->prepare($query);
152 $sth->execute($codestring);
153 ($resultstring)=$sth->fetchrow;
154 return $resultstring;
155 } else {
156 my $sth =
157 C4::Context->dbh->prepare(
158 "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
160 $sth->execute( $advanced_search_types, $codestring );
161 my $data = $sth->fetchrow_hashref;
162 return $$data{'lib'};
166 =head2 GetSupportList
168 $itemtypes = &GetSupportList();
170 Returns an array ref containing informations about Support (since itemtype is rather a circulation code when item-level-itypes is used).
172 build a HTML select with the following code :
174 =head3 in PERL SCRIPT
176 my $itemtypes = GetSupportList();
177 $template->param(itemtypeloop => $itemtypes);
179 =head3 in TEMPLATE
181 <select name="itemtype" id="itemtype">
182 <option value=""></option>
183 [% FOREACH itemtypeloo IN itemtypeloop %]
184 [% IF ( itemtypeloo.selected ) %]
185 <option value="[% itemtypeloo.itemtype %]" selected="selected">[% itemtypeloo.description %]</option>
186 [% ELSE %]
187 <option value="[% itemtypeloo.itemtype %]">[% itemtypeloo.description %]</option>
188 [% END %]
189 [% END %]
190 </select>
192 =cut
194 sub GetSupportList{
195 my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes");
196 if (!$advanced_search_types or $advanced_search_types =~ /itemtypes/) {
197 return GetItemTypes( style => 'array' );
198 } else {
199 my $advsearchtypes = GetAuthorisedValues($advanced_search_types);
200 my @results= map {{itemtype=>$$_{authorised_value},description=>$$_{lib},imageurl=>$$_{imageurl}}} @$advsearchtypes;
201 return \@results;
204 =head2 GetItemTypes
206 $itemtypes = &GetItemTypes( style => $style );
208 Returns information about existing itemtypes.
210 Params:
211 style: either 'array' or 'hash', defaults to 'hash'.
212 'array' returns an arrayref,
213 'hash' return a hashref with the itemtype value as the key
215 build a HTML select with the following code :
217 =head3 in PERL SCRIPT
219 my $itemtypes = GetItemTypes;
220 my @itemtypesloop;
221 foreach my $thisitemtype (sort keys %$itemtypes) {
222 my $selected = 1 if $thisitemtype eq $itemtype;
223 my %row =(value => $thisitemtype,
224 selected => $selected,
225 description => $itemtypes->{$thisitemtype}->{'description'},
227 push @itemtypesloop, \%row;
229 $template->param(itemtypeloop => \@itemtypesloop);
231 =head3 in TEMPLATE
233 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
234 <select name="itemtype">
235 <option value="">Default</option>
236 <!-- TMPL_LOOP name="itemtypeloop" -->
237 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="description" --></option>
238 <!-- /TMPL_LOOP -->
239 </select>
240 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
241 <input type="submit" value="OK" class="button">
242 </form>
244 =cut
246 sub GetItemTypes {
247 my ( %params ) = @_;
248 my $style = defined( $params{'style'} ) ? $params{'style'} : 'hash';
250 require C4::Languages;
251 my $language = C4::Languages::getlanguage();
252 # returns a reference to a hash of references to itemtypes...
253 my $dbh = C4::Context->dbh;
254 my $query = q|
255 SELECT
256 itemtypes.itemtype,
257 itemtypes.description,
258 itemtypes.rentalcharge,
259 itemtypes.notforloan,
260 itemtypes.imageurl,
261 itemtypes.summary,
262 itemtypes.checkinmsg,
263 itemtypes.checkinmsgtype,
264 itemtypes.sip_media_type,
265 itemtypes.hideinopac,
266 itemtypes.searchcategory,
267 COALESCE( localization.translation, itemtypes.description ) AS translated_description
268 FROM itemtypes
269 LEFT JOIN localization ON itemtypes.itemtype = localization.code
270 AND localization.entity = 'itemtypes'
271 AND localization.lang = ?
272 ORDER BY itemtype
274 my $sth = $dbh->prepare($query);
275 $sth->execute( $language );
277 if ( $style eq 'hash' ) {
278 my %itemtypes;
279 while ( my $IT = $sth->fetchrow_hashref ) {
280 $itemtypes{ $IT->{'itemtype'} } = $IT;
282 return ( \%itemtypes );
283 } else {
284 return [ sort { lc $a->{translated_description} cmp lc $b->{translated_description} } @{ $sth->fetchall_arrayref( {} ) } ];
288 =head2 GetItemTypesCategorized
290 $categories = GetItemTypesCategorized();
292 Returns a hashref containing search categories.
293 A search category will be put in the hash if at least one of its itemtypes is visible in OPAC.
294 The categories must be part of Authorized Values (ITEMTYPECAT)
296 =cut
298 sub GetItemTypesCategorized {
299 my $dbh = C4::Context->dbh;
300 # Order is important, so that partially hidden (some items are not visible in OPAC) search
301 # categories will be visible. hideinopac=0 must be last.
302 my $query = q|
303 SELECT itemtype, description, imageurl, hideinopac, 0 as 'iscat' FROM itemtypes WHERE ISNULL(searchcategory) or length(searchcategory) = 0
304 UNION
305 SELECT DISTINCT searchcategory AS `itemtype`,
306 authorised_values.lib_opac AS description,
307 authorised_values.imageurl AS imageurl,
308 hideinopac, 1 as 'iscat'
309 FROM itemtypes
310 LEFT JOIN authorised_values ON searchcategory = authorised_value
311 WHERE searchcategory > '' and hideinopac=1
312 UNION
313 SELECT DISTINCT searchcategory AS `itemtype`,
314 authorised_values.lib_opac AS description,
315 authorised_values.imageurl AS imageurl,
316 hideinopac, 1 as 'iscat'
317 FROM itemtypes
318 LEFT JOIN authorised_values ON searchcategory = authorised_value
319 WHERE searchcategory > '' and hideinopac=0
321 return ($dbh->selectall_hashref($query,'itemtype'));
324 =head2 GetItemTypesByCategory
326 @results = GetItemTypesByCategory( $searchcategory );
328 Returns the itemtype code of all itemtypes included in a searchcategory.
330 =cut
332 sub GetItemTypesByCategory {
333 my ($category) = @_;
334 my $count = 0;
335 my @results;
336 my $dbh = C4::Context->dbh;
337 my $query = qq|SELECT itemtype FROM itemtypes WHERE searchcategory=?|;
338 my $tmp=$dbh->selectcol_arrayref($query,undef,$category);
339 return @$tmp;
342 sub get_itemtypeinfos_of {
343 my @itemtypes = @_;
345 my $placeholders = join( ', ', map { '?' } @itemtypes );
346 my $query = <<"END_SQL";
347 SELECT itemtype,
348 description,
349 imageurl,
350 notforloan
351 FROM itemtypes
352 WHERE itemtype IN ( $placeholders )
353 END_SQL
355 return get_infos_of( $query, 'itemtype', undef, \@itemtypes );
358 =head2 getframework
360 $frameworks = &getframework();
362 Returns information about existing frameworks
364 build a HTML select with the following code :
366 =head3 in PERL SCRIPT
368 my $frameworks = getframeworks();
369 my @frameworkloop;
370 foreach my $thisframework (keys %$frameworks) {
371 my $selected = 1 if $thisframework eq $frameworkcode;
372 my %row =(
373 value => $thisframework,
374 selected => $selected,
375 description => $frameworks->{$thisframework}->{'frameworktext'},
377 push @frameworksloop, \%row;
379 $template->param(frameworkloop => \@frameworksloop);
381 =head3 in TEMPLATE
383 <form action="[% script_name %] method=post>
384 <select name="frameworkcode">
385 <option value="">Default</option>
386 [% FOREACH framework IN frameworkloop %]
387 [% IF ( framework.selected ) %]
388 <option value="[% framework.value %]" selected="selected">[% framework.description %]</option>
389 [% ELSE %]
390 <option value="[% framework.value %]">[% framework.description %]</option>
391 [% END %]
392 [% END %]
393 </select>
394 <input type=text name=searchfield value="[% searchfield %]">
395 <input type="submit" value="OK" class="button">
396 </form>
398 =cut
400 sub getframeworks {
402 # returns a reference to a hash of references to branches...
403 my %itemtypes;
404 my $dbh = C4::Context->dbh;
405 my $sth = $dbh->prepare("select * from biblio_framework");
406 $sth->execute;
407 while ( my $IT = $sth->fetchrow_hashref ) {
408 $itemtypes{ $IT->{'frameworkcode'} } = $IT;
410 return ( \%itemtypes );
413 =head2 GetFrameworksLoop
415 $frameworks = GetFrameworksLoop( $frameworkcode );
417 Returns the loop suggested on getframework(), but ordered by framework description.
419 build a HTML select with the following code :
421 =head3 in PERL SCRIPT
423 $template->param( frameworkloop => GetFrameworksLoop( $frameworkcode ) );
425 =head3 in TEMPLATE
427 Same as getframework()
429 <form action="[% script_name %] method=post>
430 <select name="frameworkcode">
431 <option value="">Default</option>
432 [% FOREACH framework IN frameworkloop %]
433 [% IF ( framework.selected ) %]
434 <option value="[% framework.value %]" selected="selected">[% framework.description %]</option>
435 [% ELSE %]
436 <option value="[% framework.value %]">[% framework.description %]</option>
437 [% END %]
438 [% END %]
439 </select>
440 <input type=text name=searchfield value="[% searchfield %]">
441 <input type="submit" value="OK" class="button">
442 </form>
444 =cut
446 sub GetFrameworksLoop {
447 my $frameworkcode = shift;
448 my $frameworks = getframeworks();
449 my @frameworkloop;
450 foreach my $thisframework (sort { uc($frameworks->{$a}->{'frameworktext'}) cmp uc($frameworks->{$b}->{'frameworktext'}) } keys %$frameworks) {
451 my $selected = ( $thisframework eq $frameworkcode ) ? 1 : undef;
452 my %row = (
453 value => $thisframework,
454 selected => $selected,
455 description => $frameworks->{$thisframework}->{'frameworktext'},
457 push @frameworkloop, \%row;
459 return \@frameworkloop;
462 =head2 getframeworkinfo
464 $frameworkinfo = &getframeworkinfo($frameworkcode);
466 Returns information about an frameworkcode.
468 =cut
470 sub getframeworkinfo {
471 my ($frameworkcode) = @_;
472 my $dbh = C4::Context->dbh;
473 my $sth =
474 $dbh->prepare("select * from biblio_framework where frameworkcode=?");
475 $sth->execute($frameworkcode);
476 my $res = $sth->fetchrow_hashref;
477 return $res;
480 =head2 getitemtypeinfo
482 $itemtype = &getitemtypeinfo($itemtype, [$interface]);
484 Returns information about an itemtype. The optional $interface argument
485 sets which interface ('opac' or 'intranet') to return the imageurl for.
486 Defaults to intranet.
488 =cut
490 sub getitemtypeinfo {
491 my ($itemtype, $interface) = @_;
492 my $dbh = C4::Context->dbh;
493 require C4::Languages;
494 my $language = C4::Languages::getlanguage();
495 my $it = $dbh->selectrow_hashref(q|
496 SELECT
497 itemtypes.itemtype,
498 itemtypes.description,
499 itemtypes.rentalcharge,
500 itemtypes.notforloan,
501 itemtypes.imageurl,
502 itemtypes.summary,
503 itemtypes.checkinmsg,
504 itemtypes.checkinmsgtype,
505 itemtypes.sip_media_type,
506 COALESCE( localization.translation, itemtypes.description ) AS translated_description
507 FROM itemtypes
508 LEFT JOIN localization ON itemtypes.itemtype = localization.code
509 AND localization.entity = 'itemtypes'
510 AND localization.lang = ?
511 WHERE itemtypes.itemtype = ?
512 |, undef, $language, $itemtype );
514 $it->{imageurl} = getitemtypeimagelocation( ( ( defined $interface && $interface eq 'opac' ) ? 'opac' : 'intranet' ), $it->{imageurl} );
516 return $it;
519 =head2 getitemtypeimagedir
521 my $directory = getitemtypeimagedir( 'opac' );
523 pass in 'opac' or 'intranet'. Defaults to 'opac'.
525 returns the full path to the appropriate directory containing images.
527 =cut
529 sub getitemtypeimagedir {
530 my $src = shift || 'opac';
531 if ($src eq 'intranet') {
532 return C4::Context->config('intrahtdocs') . '/' .C4::Context->preference('template') . '/img/itemtypeimg';
533 } else {
534 return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
538 sub getitemtypeimagesrc {
539 my $src = shift || 'opac';
540 if ($src eq 'intranet') {
541 return '/intranet-tmpl' . '/' . C4::Context->preference('template') . '/img/itemtypeimg';
542 } else {
543 return '/opac-tmpl' . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
547 sub getitemtypeimagelocation {
548 my ( $src, $image ) = @_;
550 return '' if ( !$image );
551 require URI::Split;
553 my $scheme = ( URI::Split::uri_split( $image ) )[0];
555 return $image if ( $scheme );
557 return getitemtypeimagesrc( $src ) . '/' . $image;
560 =head3 _getImagesFromDirectory
562 Find all of the image files in a directory in the filesystem
564 parameters: a directory name
566 returns: a list of images in that directory.
568 Notes: this does not traverse into subdirectories. See
569 _getSubdirectoryNames for help with that.
570 Images are assumed to be files with .gif or .png file extensions.
571 The image names returned do not have the directory name on them.
573 =cut
575 sub _getImagesFromDirectory {
576 my $directoryname = shift;
577 return unless defined $directoryname;
578 return unless -d $directoryname;
580 if ( opendir ( my $dh, $directoryname ) ) {
581 my @images = grep { /\.(gif|png)$/i } readdir( $dh );
582 closedir $dh;
583 @images = sort(@images);
584 return @images;
585 } else {
586 warn "unable to opendir $directoryname: $!";
587 return;
591 =head3 _getSubdirectoryNames
593 Find all of the directories in a directory in the filesystem
595 parameters: a directory name
597 returns: a list of subdirectories in that directory.
599 Notes: this does not traverse into subdirectories. Only the first
600 level of subdirectories are returned.
601 The directory names returned don't have the parent directory name on them.
603 =cut
605 sub _getSubdirectoryNames {
606 my $directoryname = shift;
607 return unless defined $directoryname;
608 return unless -d $directoryname;
610 if ( opendir ( my $dh, $directoryname ) ) {
611 my @directories = grep { -d File::Spec->catfile( $directoryname, $_ ) && ! ( /^\./ ) } readdir( $dh );
612 closedir $dh;
613 return @directories;
614 } else {
615 warn "unable to opendir $directoryname: $!";
616 return;
620 =head3 getImageSets
622 returns: a listref of hashrefs. Each hash represents another collection of images.
624 { imagesetname => 'npl', # the name of the image set (npl is the original one)
625 images => listref of image hashrefs
628 each image is represented by a hashref like this:
630 { KohaImage => 'npl/image.gif',
631 StaffImageUrl => '/intranet-tmpl/prog/img/itemtypeimg/npl/image.gif',
632 OpacImageURL => '/opac-tmpl/prog/itemtypeimg/npl/image.gif'
633 checked => 0 or 1: was this the image passed to this method?
634 Note: I'd like to remove this somehow.
637 =cut
639 sub getImageSets {
640 my %params = @_;
641 my $checked = $params{'checked'} || '';
643 my $paths = { staff => { filesystem => getitemtypeimagedir('intranet'),
644 url => getitemtypeimagesrc('intranet'),
646 opac => { filesystem => getitemtypeimagedir('opac'),
647 url => getitemtypeimagesrc('opac'),
651 my @imagesets = (); # list of hasrefs of image set data to pass to template
652 my @subdirectories = _getSubdirectoryNames( $paths->{'staff'}{'filesystem'} );
653 foreach my $imagesubdir ( @subdirectories ) {
654 warn $imagesubdir if $DEBUG;
655 my @imagelist = (); # hashrefs of image info
656 my @imagenames = _getImagesFromDirectory( File::Spec->catfile( $paths->{'staff'}{'filesystem'}, $imagesubdir ) );
657 my $imagesetactive = 0;
658 foreach my $thisimage ( @imagenames ) {
659 push( @imagelist,
660 { KohaImage => "$imagesubdir/$thisimage",
661 StaffImageUrl => join( '/', $paths->{'staff'}{'url'}, $imagesubdir, $thisimage ),
662 OpacImageUrl => join( '/', $paths->{'opac'}{'url'}, $imagesubdir, $thisimage ),
663 checked => "$imagesubdir/$thisimage" eq $checked ? 1 : 0,
666 $imagesetactive = 1 if "$imagesubdir/$thisimage" eq $checked;
668 push @imagesets, { imagesetname => $imagesubdir,
669 imagesetactive => $imagesetactive,
670 images => \@imagelist };
673 return \@imagesets;
676 =head2 GetPrinters
678 $printers = &GetPrinters();
679 @queues = keys %$printers;
681 Returns information about existing printer queues.
683 C<$printers> is a reference-to-hash whose keys are the print queues
684 defined in the printers table of the Koha database. The values are
685 references-to-hash, whose keys are the fields in the printers table.
687 =cut
689 sub GetPrinters {
690 my %printers;
691 my $dbh = C4::Context->dbh;
692 my $sth = $dbh->prepare("select * from printers");
693 $sth->execute;
694 while ( my $printer = $sth->fetchrow_hashref ) {
695 $printers{ $printer->{'printqueue'} } = $printer;
697 return ( \%printers );
700 =head2 GetPrinter
702 $printer = GetPrinter( $query, $printers );
704 =cut
706 sub GetPrinter {
707 my ( $query, $printers ) = @_; # get printer for this query from printers
708 my $printer = $query->param('printer');
709 my %cookie = $query->cookie('userenv');
710 ($printer) || ( $printer = $cookie{'printer'} ) || ( $printer = '' );
711 ( $printers->{$printer} ) || ( $printer = ( keys %$printers )[0] );
712 return $printer;
715 =head2 getnbpages
717 Returns the number of pages to display in a pagination bar, given the number
718 of items and the number of items per page.
720 =cut
722 sub getnbpages {
723 my ( $nb_items, $nb_items_per_page ) = @_;
725 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
728 =head2 getallthemes
730 (@themes) = &getallthemes('opac');
731 (@themes) = &getallthemes('intranet');
733 Returns an array of all available themes.
735 =cut
737 sub getallthemes {
738 my $type = shift;
739 my $htdocs;
740 my @themes;
741 if ( $type eq 'intranet' ) {
742 $htdocs = C4::Context->config('intrahtdocs');
744 else {
745 $htdocs = C4::Context->config('opachtdocs');
747 opendir D, "$htdocs";
748 my @dirlist = readdir D;
749 foreach my $directory (@dirlist) {
750 next if $directory eq 'lib';
751 -d "$htdocs/$directory/en" and push @themes, $directory;
753 return @themes;
756 sub getFacets {
757 my $facets;
758 if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
759 $facets = [
761 idx => 'su-to',
762 label => 'Topics',
763 tags => [ qw/ 600ab 601ab 602a 604at 605a 606ax 610a / ],
764 sep => ' - ',
767 idx => 'su-geo',
768 label => 'Places',
769 tags => [ qw/ 607a / ],
770 sep => ' - ',
773 idx => 'su-ut',
774 label => 'Titles',
775 tags => [ qw/ 500a 501a 503a / ],
776 sep => ', ',
779 idx => 'au',
780 label => 'Authors',
781 tags => [ qw/ 700ab 701ab 702ab / ],
782 sep => C4::Context->preference("UNIMARCAuthorsFacetsSeparator"),
785 idx => 'se',
786 label => 'Series',
787 tags => [ qw/ 225a / ],
788 sep => ', ',
791 idx => 'location',
792 label => 'Location',
793 tags => [ qw/ 995e / ],
797 unless ( C4::Context->preference("singleBranchMode")
798 || Koha::Libraries->search->count == 1 )
800 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
801 if ( $DisplayLibraryFacets eq 'both'
802 || $DisplayLibraryFacets eq 'holding' )
804 push(
805 @$facets,
807 idx => 'holdingbranch',
808 label => 'HoldingLibrary',
809 tags => [qw / 995c /],
814 if ( $DisplayLibraryFacets eq 'both'
815 || $DisplayLibraryFacets eq 'home' )
817 push(
818 @$facets,
820 idx => 'homebranch',
821 label => 'HomeLibrary',
822 tags => [qw / 995b /],
828 else {
829 $facets = [
831 idx => 'su-to',
832 label => 'Topics',
833 tags => [ qw/ 650a / ],
834 sep => '--',
837 # idx => 'su-na',
838 # label => 'People and Organizations',
839 # tags => [ qw/ 600a 610a 611a / ],
840 # sep => 'a',
841 # },
843 idx => 'su-geo',
844 label => 'Places',
845 tags => [ qw/ 651a / ],
846 sep => '--',
849 idx => 'su-ut',
850 label => 'Titles',
851 tags => [ qw/ 630a / ],
852 sep => '--',
855 idx => 'au',
856 label => 'Authors',
857 tags => [ qw/ 100a 110a 700a / ],
858 sep => ', ',
861 idx => 'se',
862 label => 'Series',
863 tags => [ qw/ 440a 490a / ],
864 sep => ', ',
867 idx => 'itype',
868 label => 'ItemTypes',
869 tags => [ qw/ 952y 942c / ],
870 sep => ', ',
873 idx => 'location',
874 label => 'Location',
875 tags => [ qw / 952c / ],
879 unless ( C4::Context->preference("singleBranchMode")
880 || Koha::Libraries->search->count == 1 )
882 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
883 if ( $DisplayLibraryFacets eq 'both'
884 || $DisplayLibraryFacets eq 'holding' )
886 push(
887 @$facets,
889 idx => 'holdingbranch',
890 label => 'HoldingLibrary',
891 tags => [qw / 952b /],
896 if ( $DisplayLibraryFacets eq 'both'
897 || $DisplayLibraryFacets eq 'home' )
899 push(
900 @$facets,
902 idx => 'homebranch',
903 label => 'HomeLibrary',
904 tags => [qw / 952a /],
910 return $facets;
913 =head2 get_infos_of
915 Return a href where a key is associated to a href. You give a query,
916 the name of the key among the fields returned by the query. If you
917 also give as third argument the name of the value, the function
918 returns a href of scalar. The optional 4th argument is an arrayref of
919 items passed to the C<execute()> call. It is designed to bind
920 parameters to any placeholders in your SQL.
922 my $query = '
923 SELECT itemnumber,
924 notforloan,
925 barcode
926 FROM items
929 # generic href of any information on the item, href of href.
930 my $iteminfos_of = get_infos_of($query, 'itemnumber');
931 print $iteminfos_of->{$itemnumber}{barcode};
933 # specific information, href of scalar
934 my $barcode_of_item = get_infos_of($query, 'itemnumber', 'barcode');
935 print $barcode_of_item->{$itemnumber};
937 =cut
939 sub get_infos_of {
940 my ( $query, $key_name, $value_name, $bind_params ) = @_;
942 my $dbh = C4::Context->dbh;
944 my $sth = $dbh->prepare($query);
945 $sth->execute( @$bind_params );
947 my %infos_of;
948 while ( my $row = $sth->fetchrow_hashref ) {
949 if ( defined $value_name ) {
950 $infos_of{ $row->{$key_name} } = $row->{$value_name};
952 else {
953 $infos_of{ $row->{$key_name} } = $row;
956 $sth->finish;
958 return \%infos_of;
961 =head2 get_notforloan_label_of
963 my $notforloan_label_of = get_notforloan_label_of();
965 Each authorised value of notforloan (information available in items and
966 itemtypes) is link to a single label.
968 Returns a href where keys are authorised values and values are corresponding
969 labels.
971 foreach my $authorised_value (keys %{$notforloan_label_of}) {
972 printf(
973 "authorised_value: %s => %s\n",
974 $authorised_value,
975 $notforloan_label_of->{$authorised_value}
979 =cut
981 # FIXME - why not use GetAuthorisedValues ??
983 sub get_notforloan_label_of {
984 my $dbh = C4::Context->dbh;
986 my $query = '
987 SELECT authorised_value
988 FROM marc_subfield_structure
989 WHERE kohafield = \'items.notforloan\'
990 LIMIT 0, 1
992 my $sth = $dbh->prepare($query);
993 $sth->execute();
994 my ($statuscode) = $sth->fetchrow_array();
996 $query = '
997 SELECT lib,
998 authorised_value
999 FROM authorised_values
1000 WHERE category = ?
1002 $sth = $dbh->prepare($query);
1003 $sth->execute($statuscode);
1004 my %notforloan_label_of;
1005 while ( my $row = $sth->fetchrow_hashref ) {
1006 $notforloan_label_of{ $row->{authorised_value} } = $row->{lib};
1008 $sth->finish;
1010 return \%notforloan_label_of;
1013 =head2 displayServers
1015 my $servers = displayServers();
1016 my $servers = displayServers( $position );
1017 my $servers = displayServers( $position, $type );
1019 displayServers returns a listref of hashrefs, each containing
1020 information about available z3950 servers. Each hashref has a format
1021 like:
1024 'checked' => 'checked',
1025 'encoding' => 'utf8',
1026 'icon' => undef,
1027 'id' => 'LIBRARY OF CONGRESS',
1028 'label' => '',
1029 'name' => 'server',
1030 'opensearch' => '',
1031 'value' => 'lx2.loc.gov:210/',
1032 'zed' => 1,
1035 =cut
1037 sub displayServers {
1038 my ( $position, $type ) = @_;
1039 my $dbh = C4::Context->dbh;
1041 my $strsth = 'SELECT * FROM z3950servers';
1042 my @where_clauses;
1043 my @bind_params;
1045 if ($position) {
1046 push @bind_params, $position;
1047 push @where_clauses, ' position = ? ';
1050 if ($type) {
1051 push @bind_params, $type;
1052 push @where_clauses, ' type = ? ';
1055 # reassemble where clause from where clause pieces
1056 if (@where_clauses) {
1057 $strsth .= ' WHERE ' . join( ' AND ', @where_clauses );
1060 my $rq = $dbh->prepare($strsth);
1061 $rq->execute(@bind_params);
1062 my @primaryserverloop;
1064 while ( my $data = $rq->fetchrow_hashref ) {
1065 push @primaryserverloop,
1066 { label => $data->{description},
1067 id => $data->{name},
1068 name => "server",
1069 value => $data->{host} . ":" . $data->{port} . "/" . $data->{database},
1070 encoding => ( $data->{encoding} ? $data->{encoding} : "iso-5426" ),
1071 checked => "checked",
1072 icon => $data->{icon},
1073 zed => $data->{type} eq 'zed',
1074 opensearch => $data->{type} eq 'opensearch'
1077 return \@primaryserverloop;
1081 =head2 GetKohaImageurlFromAuthorisedValues
1083 $authhorised_value = GetKohaImageurlFromAuthorisedValues( $category, $authvalcode );
1085 Return the first url of the authorised value image represented by $lib.
1087 =cut
1089 sub GetKohaImageurlFromAuthorisedValues {
1090 my ( $category, $lib ) = @_;
1091 my $dbh = C4::Context->dbh;
1092 my $sth = $dbh->prepare("SELECT imageurl FROM authorised_values WHERE category=? AND lib =?");
1093 $sth->execute( $category, $lib );
1094 while ( my $data = $sth->fetchrow_hashref ) {
1095 return $data->{'imageurl'};
1099 =head2 GetAuthValCode
1101 $authvalcode = GetAuthValCode($kohafield,$frameworkcode);
1103 =cut
1105 sub GetAuthValCode {
1106 my ($kohafield,$fwcode) = @_;
1107 my $dbh = C4::Context->dbh;
1108 $fwcode='' unless $fwcode;
1109 my $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield=? and frameworkcode=?');
1110 $sth->execute($kohafield,$fwcode);
1111 my ($authvalcode) = $sth->fetchrow_array;
1112 return $authvalcode;
1115 =head2 GetAuthValCodeFromField
1117 $authvalcode = GetAuthValCodeFromField($field,$subfield,$frameworkcode);
1119 C<$subfield> can be undefined
1121 =cut
1123 sub GetAuthValCodeFromField {
1124 my ($field,$subfield,$fwcode) = @_;
1125 my $dbh = C4::Context->dbh;
1126 $fwcode='' unless $fwcode;
1127 my $sth;
1128 if (defined $subfield) {
1129 $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where tagfield=? and tagsubfield=? and frameworkcode=?');
1130 $sth->execute($field,$subfield,$fwcode);
1131 } else {
1132 $sth = $dbh->prepare('select authorised_value from marc_tag_structure where tagfield=? and frameworkcode=?');
1133 $sth->execute($field,$fwcode);
1135 my ($authvalcode) = $sth->fetchrow_array;
1136 return $authvalcode;
1139 =head2 GetAuthorisedValues
1141 $authvalues = GetAuthorisedValues([$category], [$selected]);
1143 This function returns all authorised values from the'authorised_value' table in a reference to array of hashrefs.
1145 C<$category> returns authorised values for just one category (optional).
1147 C<$selected> adds a "selected => 1" entry to the hash if the
1148 authorised_value matches it. B<NOTE:> this feature should be considered
1149 deprecated as it may be removed in the future.
1151 C<$opac> If set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1153 =cut
1155 sub GetAuthorisedValues {
1156 my ( $category, $selected, $opac ) = @_;
1158 # TODO: the "selected" feature should be replaced by a utility function
1159 # somewhere else, it doesn't belong in here. For starters it makes
1160 # caching much more complicated. Or just let the UI logic handle it, it's
1161 # what it's for.
1163 # Is this cached already?
1164 $opac = $opac ? 1 : 0; # normalise to be safe
1165 my $branch_limit =
1166 C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
1167 my $selected_key = defined($selected) ? $selected : '';
1168 my $cache_key =
1169 "AuthorisedValues-$category-$selected_key-$opac-$branch_limit";
1170 my $cache = Koha::Cache->get_instance();
1171 my $result = $cache->get_from_cache($cache_key);
1172 return $result if $result;
1174 my @results;
1175 my $dbh = C4::Context->dbh;
1176 my $query = qq{
1177 SELECT *
1178 FROM authorised_values
1180 $query .= qq{
1181 LEFT JOIN authorised_values_branches ON ( id = av_id )
1182 } if $branch_limit;
1183 my @where_strings;
1184 my @where_args;
1185 if($category) {
1186 push @where_strings, "category = ?";
1187 push @where_args, $category;
1189 if($branch_limit) {
1190 push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
1191 push @where_args, $branch_limit;
1193 if(@where_strings > 0) {
1194 $query .= " WHERE " . join(" AND ", @where_strings);
1196 $query .= " GROUP BY lib";
1197 $query .= ' ORDER BY category, ' . (
1198 $opac ? 'COALESCE(lib_opac, lib)'
1199 : 'lib, lib_opac'
1202 my $sth = $dbh->prepare($query);
1204 $sth->execute( @where_args );
1205 while (my $data=$sth->fetchrow_hashref) {
1206 if ( defined $selected and $selected eq $data->{authorised_value} ) {
1207 $data->{selected} = 1;
1209 else {
1210 $data->{selected} = 0;
1213 if ($opac && $data->{lib_opac}) {
1214 $data->{lib} = $data->{lib_opac};
1216 push @results, $data;
1218 $sth->finish;
1220 # We can't cache for long because of that "selected" thing which
1221 # makes it impossible to clear the cache without iterating through every
1222 # value, which sucks. This'll cover this request, and not a whole lot more.
1223 $cache->set_in_cache( $cache_key, \@results, { deepcopy => 1, expiry => 5 } );
1224 return \@results;
1227 =head2 GetAuthorisedValueCategories
1229 $auth_categories = GetAuthorisedValueCategories();
1231 Return an arrayref of all of the available authorised
1232 value categories.
1234 =cut
1236 sub GetAuthorisedValueCategories {
1237 my $dbh = C4::Context->dbh;
1238 my $sth = $dbh->prepare("SELECT DISTINCT category FROM authorised_values ORDER BY category");
1239 $sth->execute;
1240 my @results;
1241 while (defined (my $category = $sth->fetchrow_array) ) {
1242 push @results, $category;
1244 return \@results;
1247 =head2 IsAuthorisedValueCategory
1249 $is_auth_val_category = IsAuthorisedValueCategory($category);
1251 Returns whether a given category name is a valid one
1253 =cut
1255 sub IsAuthorisedValueCategory {
1256 my $category = shift;
1257 my $query = '
1258 SELECT category
1259 FROM authorised_values
1260 WHERE category=?
1261 LIMIT 1
1263 my $sth = C4::Context->dbh->prepare($query);
1264 $sth->execute($category);
1265 $sth->fetchrow ? return 1
1266 : return 0;
1269 =head2 GetAuthorisedValueByCode
1271 $authorised_value = GetAuthorisedValueByCode( $category, $authvalcode, $opac );
1273 Return the lib attribute from authorised_values from the row identified
1274 by the passed category and code
1276 =cut
1278 sub GetAuthorisedValueByCode {
1279 my ( $category, $authvalcode, $opac ) = @_;
1281 my $field = $opac ? 'lib_opac' : 'lib';
1282 my $dbh = C4::Context->dbh;
1283 my $sth = $dbh->prepare("SELECT $field FROM authorised_values WHERE category=? AND authorised_value =?");
1284 $sth->execute( $category, $authvalcode );
1285 while ( my $data = $sth->fetchrow_hashref ) {
1286 return $data->{ $field };
1290 =head2 GetKohaAuthorisedValues
1292 Takes $kohafield, $fwcode as parameters.
1294 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1296 Returns hashref of Code => description
1298 Returns undef if no authorised value category is defined for the kohafield.
1300 =cut
1302 sub GetKohaAuthorisedValues {
1303 my ($kohafield,$fwcode,$opac) = @_;
1304 $fwcode='' unless $fwcode;
1305 my %values;
1306 my $dbh = C4::Context->dbh;
1307 my $avcode = GetAuthValCode($kohafield,$fwcode);
1308 if ($avcode) {
1309 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1310 $sth->execute($avcode);
1311 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1312 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1314 return \%values;
1315 } else {
1316 return;
1320 =head2 GetKohaAuthorisedValuesFromField
1322 Takes $field, $subfield, $fwcode as parameters.
1324 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1325 $subfield can be undefined
1327 Returns hashref of Code => description
1329 Returns undef if no authorised value category is defined for the given field and subfield
1331 =cut
1333 sub GetKohaAuthorisedValuesFromField {
1334 my ($field, $subfield, $fwcode,$opac) = @_;
1335 $fwcode='' unless $fwcode;
1336 my %values;
1337 my $dbh = C4::Context->dbh;
1338 my $avcode = GetAuthValCodeFromField($field, $subfield, $fwcode);
1339 if ($avcode) {
1340 my $sth = $dbh->prepare("select authorised_value, lib, lib_opac from authorised_values where category=? ");
1341 $sth->execute($avcode);
1342 while ( my ($val, $lib, $lib_opac) = $sth->fetchrow_array ) {
1343 $values{$val} = ($opac && $lib_opac) ? $lib_opac : $lib;
1345 return \%values;
1346 } else {
1347 return;
1351 =head2 GetKohaAuthorisedValuesMapping
1353 Takes a hash as a parameter. The interface key indicates the
1354 description to use in the mapping.
1356 Returns hashref of:
1357 "{kohafield},{frameworkcode},{authorised_value}" => "{description}"
1358 for all the kohafields, frameworkcodes, and authorised values.
1360 Returns undef if nothing is found.
1362 =cut
1364 sub GetKohaAuthorisedValuesMapping {
1365 my ($parameter) = @_;
1366 my $interface = $parameter->{'interface'} // '';
1368 my $query_mapping = q{
1369 SELECT TA.kohafield,TA.authorised_value AS category,
1370 TA.frameworkcode,TB.authorised_value,
1371 IF(TB.lib_opac>'',TB.lib_opac,TB.lib) AS OPAC,
1372 TB.lib AS Intranet,TB.lib_opac
1373 FROM marc_subfield_structure AS TA JOIN
1374 authorised_values as TB ON
1375 TA.authorised_value=TB.category
1376 WHERE TA.kohafield>'' AND TA.authorised_value>'';
1378 my $dbh = C4::Context->dbh;
1379 my $sth = $dbh->prepare($query_mapping);
1380 $sth->execute();
1381 my $avmapping;
1382 if ($interface eq 'opac') {
1383 while (my $row = $sth->fetchrow_hashref) {
1384 $avmapping->{$row->{kohafield}.",".$row->{frameworkcode}.",".$row->{authorised_value}} = $row->{OPAC};
1387 else {
1388 while (my $row = $sth->fetchrow_hashref) {
1389 $avmapping->{$row->{kohafield}.",".$row->{frameworkcode}.",".$row->{authorised_value}} = $row->{Intranet};
1392 return $avmapping;
1395 =head2 xml_escape
1397 my $escaped_string = C4::Koha::xml_escape($string);
1399 Convert &, <, >, ', and " in a string to XML entities
1401 =cut
1403 sub xml_escape {
1404 my $str = shift;
1405 return '' unless defined $str;
1406 $str =~ s/&/&amp;/g;
1407 $str =~ s/</&lt;/g;
1408 $str =~ s/>/&gt;/g;
1409 $str =~ s/'/&apos;/g;
1410 $str =~ s/"/&quot;/g;
1411 return $str;
1414 =head2 GetKohaAuthorisedValueLib
1416 Takes $category, $authorised_value as parameters.
1418 If $opac parameter is set to a true value, displays OPAC descriptions rather than normal ones when they exist.
1420 Returns authorised value description
1422 =cut
1424 sub GetKohaAuthorisedValueLib {
1425 my ($category,$authorised_value,$opac) = @_;
1426 my $value;
1427 my $dbh = C4::Context->dbh;
1428 my $sth = $dbh->prepare("select lib, lib_opac from authorised_values where category=? and authorised_value=?");
1429 $sth->execute($category,$authorised_value);
1430 my $data = $sth->fetchrow_hashref;
1431 $value = ($opac && $$data{'lib_opac'}) ? $$data{'lib_opac'} : $$data{'lib'};
1432 return $value;
1435 =head2 AddAuthorisedValue
1437 AddAuthorisedValue($category, $authorised_value, $lib, $lib_opac, $imageurl);
1439 Create a new authorised value.
1441 =cut
1443 sub AddAuthorisedValue {
1444 my ($category, $authorised_value, $lib, $lib_opac, $imageurl) = @_;
1446 my $dbh = C4::Context->dbh;
1447 my $query = qq{
1448 INSERT INTO authorised_values (category, authorised_value, lib, lib_opac, imageurl)
1449 VALUES (?,?,?,?,?)
1451 my $sth = $dbh->prepare($query);
1452 $sth->execute($category, $authorised_value, $lib, $lib_opac, $imageurl);
1455 =head2 display_marc_indicators
1457 my $display_form = C4::Koha::display_marc_indicators($field);
1459 C<$field> is a MARC::Field object
1461 Generate a display form of the indicators of a variable
1462 MARC field, replacing any blanks with '#'.
1464 =cut
1466 sub display_marc_indicators {
1467 my $field = shift;
1468 my $indicators = '';
1469 if ($field && $field->tag() >= 10) {
1470 $indicators = $field->indicator(1) . $field->indicator(2);
1471 $indicators =~ s/ /#/g;
1473 return $indicators;
1476 sub GetNormalizedUPC {
1477 my ($marcrecord,$marcflavour) = @_;
1479 return unless $marcrecord;
1480 if ($marcflavour eq 'UNIMARC') {
1481 my @fields = $marcrecord->field('072');
1482 foreach my $field (@fields) {
1483 my $upc = _normalize_match_point($field->subfield('a'));
1484 if ($upc) {
1485 return $upc;
1490 else { # assume marc21 if not unimarc
1491 my @fields = $marcrecord->field('024');
1492 foreach my $field (@fields) {
1493 my $indicator = $field->indicator(1);
1494 my $upc = _normalize_match_point($field->subfield('a'));
1495 if ($upc && $indicator == 1 ) {
1496 return $upc;
1502 # Normalizes and returns the first valid ISBN found in the record
1503 # ISBN13 are converted into ISBN10. This is required to get some book cover images.
1504 sub GetNormalizedISBN {
1505 my ($isbn,$marcrecord,$marcflavour) = @_;
1506 if ($isbn) {
1507 # Koha attempts to store multiple ISBNs in biblioitems.isbn, separated by " | "
1508 # anything after " | " should be removed, along with the delimiter
1509 ($isbn) = split(/\|/, $isbn );
1510 return _isbn_cleanup($isbn);
1513 return unless $marcrecord;
1515 if ($marcflavour eq 'UNIMARC') {
1516 my @fields = $marcrecord->field('010');
1517 foreach my $field (@fields) {
1518 my $isbn = $field->subfield('a');
1519 if ($isbn) {
1520 return _isbn_cleanup($isbn);
1524 else { # assume marc21 if not unimarc
1525 my @fields = $marcrecord->field('020');
1526 foreach my $field (@fields) {
1527 $isbn = $field->subfield('a');
1528 if ($isbn) {
1529 return _isbn_cleanup($isbn);
1535 sub GetNormalizedEAN {
1536 my ($marcrecord,$marcflavour) = @_;
1538 return unless $marcrecord;
1540 if ($marcflavour eq 'UNIMARC') {
1541 my @fields = $marcrecord->field('073');
1542 foreach my $field (@fields) {
1543 my $ean = _normalize_match_point($field->subfield('a'));
1544 if ( $ean ) {
1545 return $ean;
1549 else { # assume marc21 if not unimarc
1550 my @fields = $marcrecord->field('024');
1551 foreach my $field (@fields) {
1552 my $indicator = $field->indicator(1);
1553 my $ean = _normalize_match_point($field->subfield('a'));
1554 if ( $ean && $indicator == 3 ) {
1555 return $ean;
1561 sub GetNormalizedOCLCNumber {
1562 my ($marcrecord,$marcflavour) = @_;
1563 return unless $marcrecord;
1565 if ($marcflavour ne 'UNIMARC' ) {
1566 my @fields = $marcrecord->field('035');
1567 foreach my $field (@fields) {
1568 my $oclc = $field->subfield('a');
1569 if ($oclc =~ /OCoLC/) {
1570 $oclc =~ s/\(OCoLC\)//;
1571 return $oclc;
1574 } else {
1575 # TODO for UNIMARC
1577 return
1580 sub GetAuthvalueDropbox {
1581 my ( $authcat, $default ) = @_;
1582 my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
1583 my $dbh = C4::Context->dbh;
1585 my $query = qq{
1586 SELECT *
1587 FROM authorised_values
1589 $query .= qq{
1590 LEFT JOIN authorised_values_branches ON ( id = av_id )
1591 } if $branch_limit;
1592 $query .= qq{
1593 WHERE category = ?
1595 $query .= " AND ( branchcode = ? OR branchcode IS NULL )" if $branch_limit;
1596 $query .= " GROUP BY lib ORDER BY category, lib, lib_opac";
1597 my $sth = $dbh->prepare($query);
1598 $sth->execute( $authcat, $branch_limit ? $branch_limit : () );
1601 my $option_list = [];
1602 my @authorised_values = ( q{} );
1603 while (my $av = $sth->fetchrow_hashref) {
1604 push @{$option_list}, {
1605 value => $av->{authorised_value},
1606 label => $av->{lib},
1607 default => ($default eq $av->{authorised_value}),
1611 if ( @{$option_list} ) {
1612 return $option_list;
1614 return;
1618 =head2 GetDailyQuote($opts)
1620 Takes a hashref of options
1622 Currently supported options are:
1624 'id' An exact quote id
1625 'random' Select a random quote
1626 noop When no option is passed in, this sub will return the quote timestamped for the current day
1628 The function returns an anonymous hash following this format:
1631 'source' => 'source-of-quote',
1632 'timestamp' => 'timestamp-value',
1633 'text' => 'text-of-quote',
1634 'id' => 'quote-id'
1637 =cut
1639 # This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
1640 # at least for default option
1642 sub GetDailyQuote {
1643 my %opts = @_;
1644 my $dbh = C4::Context->dbh;
1645 my $query = '';
1646 my $sth = undef;
1647 my $quote = undef;
1648 if ($opts{'id'}) {
1649 $query = 'SELECT * FROM quotes WHERE id = ?';
1650 $sth = $dbh->prepare($query);
1651 $sth->execute($opts{'id'});
1652 $quote = $sth->fetchrow_hashref();
1654 elsif ($opts{'random'}) {
1655 # Fall through... we also return a random quote as a catch-all if all else fails
1657 else {
1658 $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp DESC LIMIT 0,1';
1659 $sth = $dbh->prepare($query);
1660 $sth->execute();
1661 $quote = $sth->fetchrow_hashref();
1663 unless ($quote) { # if there are not matches, choose a random quote
1664 # get a list of all available quote ids
1665 $sth = C4::Context->dbh->prepare('SELECT count(*) FROM quotes;');
1666 $sth->execute;
1667 my $range = ($sth->fetchrow_array)[0];
1668 # chose a random id within that range if there is more than one quote
1669 my $offset = int(rand($range));
1670 # grab it
1671 $query = 'SELECT * FROM quotes ORDER BY id LIMIT 1 OFFSET ?';
1672 $sth = C4::Context->dbh->prepare($query);
1673 # see http://www.perlmonks.org/?node_id=837422 for why
1674 # we're being verbose and using bind_param
1675 $sth->bind_param(1, $offset, SQL_INTEGER);
1676 $sth->execute();
1677 $quote = $sth->fetchrow_hashref();
1678 # update the timestamp for that quote
1679 $query = 'UPDATE quotes SET timestamp = ? WHERE id = ?';
1680 $sth = C4::Context->dbh->prepare($query);
1681 $sth->execute(
1682 DateTime::Format::MySQL->format_datetime( dt_from_string() ),
1683 $quote->{'id'}
1686 return $quote;
1689 sub _normalize_match_point {
1690 my $match_point = shift;
1691 (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
1692 $normalized_match_point =~ s/-//g;
1694 return $normalized_match_point;
1697 sub _isbn_cleanup {
1698 my ($isbn) = @_;
1699 return NormalizeISBN(
1701 isbn => $isbn,
1702 format => 'ISBN-10',
1703 strip_hyphens => 1,
1705 ) if $isbn;
1708 =head2 NormalizedISBN
1710 my $isbns = NormalizedISBN({
1711 isbn => $isbn,
1712 strip_hyphens => [0,1],
1713 format => ['ISBN-10', 'ISBN-13']
1716 Returns an isbn validated by Business::ISBN.
1717 Optionally strips hyphens and/or forces the isbn
1718 to be of the specified format.
1720 If the string cannot be validated as an isbn,
1721 it returns nothing.
1723 =cut
1725 sub NormalizeISBN {
1726 my ($params) = @_;
1728 my $string = $params->{isbn};
1729 my $strip_hyphens = $params->{strip_hyphens};
1730 my $format = $params->{format};
1732 return unless $string;
1734 my $isbn = Business::ISBN->new($string);
1736 if ( $isbn && $isbn->is_valid() ) {
1738 if ( $format eq 'ISBN-10' ) {
1739 $isbn = $isbn->as_isbn10();
1741 elsif ( $format eq 'ISBN-13' ) {
1742 $isbn = $isbn->as_isbn13();
1744 return unless $isbn;
1746 if ($strip_hyphens) {
1747 $string = $isbn->as_string( [] );
1748 } else {
1749 $string = $isbn->as_string();
1752 return $string;
1756 =head2 GetVariationsOfISBN
1758 my @isbns = GetVariationsOfISBN( $isbn );
1760 Returns a list of variations of the given isbn in
1761 both ISBN-10 and ISBN-13 formats, with and without
1762 hyphens.
1764 In a scalar context, the isbns are returned as a
1765 string delimited by ' | '.
1767 =cut
1769 sub GetVariationsOfISBN {
1770 my ($isbn) = @_;
1772 return unless $isbn;
1774 my @isbns;
1776 push( @isbns, NormalizeISBN({ isbn => $isbn }) );
1777 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10' }) );
1778 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13' }) );
1779 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10', strip_hyphens => 1 }) );
1780 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13', strip_hyphens => 1 }) );
1782 # Strip out any "empty" strings from the array
1783 @isbns = grep { defined($_) && $_ =~ /\S/ } @isbns;
1785 return wantarray ? @isbns : join( " | ", @isbns );
1788 =head2 GetVariationsOfISBNs
1790 my @isbns = GetVariationsOfISBNs( @isbns );
1792 Returns a list of variations of the given isbns in
1793 both ISBN-10 and ISBN-13 formats, with and without
1794 hyphens.
1796 In a scalar context, the isbns are returned as a
1797 string delimited by ' | '.
1799 =cut
1801 sub GetVariationsOfISBNs {
1802 my (@isbns) = @_;
1804 @isbns = map { GetVariationsOfISBN( $_ ) } @isbns;
1806 return wantarray ? @isbns : join( " | ", @isbns );
1809 =head2 IsKohaFieldLinked
1811 my $is_linked = IsKohaFieldLinked({
1812 kohafield => $kohafield,
1813 frameworkcode => $frameworkcode,
1816 Return 1 if the field is linked
1818 =cut
1820 sub IsKohaFieldLinked {
1821 my ( $params ) = @_;
1822 my $kohafield = $params->{kohafield};
1823 my $frameworkcode = $params->{frameworkcode} || '';
1824 my $dbh = C4::Context->dbh;
1825 my $is_linked = $dbh->selectcol_arrayref( q|
1826 SELECT COUNT(*)
1827 FROM marc_subfield_structure
1828 WHERE frameworkcode = ?
1829 AND kohafield = ?
1830 |,{}, $frameworkcode, $kohafield );
1831 return $is_linked->[0];
1836 __END__
1838 =head1 AUTHOR
1840 Koha Team
1842 =cut