3 # Copyright 2000-2002 Katipo Communications
4 # Parts Copyright 2010 Nelsonville Public Library
5 # Parts copyright 2010 BibLibre
7 # This file is part of Koha.
9 # Koha is free software; you can redistribute it and/or modify it
10 # under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
14 # Koha is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with Koha; if not, see <http://www.gnu.org/licenses>.
24 #use warnings; FIXME - Bug 2505
28 use Koha::DateUtils qw(dt_from_string);
29 use Koha::AuthorisedValues;
31 use Koha::MarcSubfieldStructures;
32 use DateTime::Format::MySQL;
35 use autouse 'Data::cselectall_arrayref' => qw(Dumper);
36 use DBI qw(:sql_types);
37 use vars qw(@ISA @EXPORT @EXPORT_OK $DEBUG);
43 &GetPrinters &GetPrinter
44 &GetItemTypes &getitemtypeinfo
45 &GetItemTypesCategorized &GetItemTypesByCategory
46 &getframeworks &getframeworkinfo
51 &get_notforloan_label_of
54 &getitemtypeimagelocation
56 &GetAuthorisedValueCategories
60 &GetNormalizedOCLCNumber
73 @EXPORT_OK = qw( GetDailyQuote );
78 C4::Koha - Perl Module containing convenience functions for Koha scripts
86 Koha.pm provides many functions for Koha scripts.
94 $itemtypes = &GetItemTypes( style => $style );
96 Returns information about existing itemtypes.
99 style: either 'array' or 'hash', defaults to 'hash'.
100 'array' returns an arrayref,
101 'hash' return a hashref with the itemtype value as the key
103 build a HTML select with the following code :
105 =head3 in PERL SCRIPT
107 my $itemtypes = GetItemTypes;
109 foreach my $thisitemtype (sort keys %$itemtypes) {
110 my $selected = 1 if $thisitemtype eq $itemtype;
111 my %row =(value => $thisitemtype,
112 selected => $selected,
113 description => $itemtypes->{$thisitemtype}->{'description'},
115 push @itemtypesloop, \%row;
117 $template->param(itemtypeloop => \@itemtypesloop);
121 <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
122 <select name="itemtype">
123 <option value="">Default</option>
124 <!-- TMPL_LOOP name="itemtypeloop" -->
125 <option value="<!-- TMPL_VAR name="value" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->><!-- TMPL_VAR name="description" --></option>
128 <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
129 <input type="submit" value="OK" class="button">
136 my $style = defined( $params{'style'} ) ? $params{'style'} : 'hash';
138 require C4::Languages;
139 my $language = C4::Languages::getlanguage();
140 # returns a reference to a hash of references to itemtypes...
141 my $dbh = C4::Context->dbh;
145 itemtypes.description,
146 itemtypes.rentalcharge,
147 itemtypes.notforloan,
150 itemtypes.checkinmsg,
151 itemtypes.checkinmsgtype,
152 itemtypes.sip_media_type,
153 itemtypes.hideinopac,
154 itemtypes.searchcategory,
155 COALESCE( localization.translation, itemtypes.description ) AS translated_description
157 LEFT JOIN localization ON itemtypes.itemtype = localization.code
158 AND localization.entity = 'itemtypes'
159 AND localization.lang = ?
162 my $sth = $dbh->prepare($query);
163 $sth->execute( $language );
165 if ( $style eq 'hash' ) {
167 while ( my $IT = $sth->fetchrow_hashref ) {
168 $itemtypes{ $IT->{'itemtype'} } = $IT;
170 return ( \%itemtypes );
172 return [ sort { lc $a->{translated_description} cmp lc $b->{translated_description} } @{ $sth->fetchall_arrayref( {} ) } ];
176 =head2 GetItemTypesCategorized
178 $categories = GetItemTypesCategorized();
180 Returns a hashref containing search categories.
181 A search category will be put in the hash if at least one of its itemtypes is visible in OPAC.
182 The categories must be part of Authorized Values (ITEMTYPECAT)
186 sub GetItemTypesCategorized {
187 my $dbh = C4::Context->dbh;
188 # Order is important, so that partially hidden (some items are not visible in OPAC) search
189 # categories will be visible. hideinopac=0 must be last.
191 SELECT itemtype, description, imageurl, hideinopac, 0 as 'iscat' FROM itemtypes WHERE ISNULL(searchcategory) or length(searchcategory) = 0
193 SELECT DISTINCT searchcategory AS `itemtype`,
194 authorised_values.lib_opac AS description,
195 authorised_values.imageurl AS imageurl,
196 hideinopac, 1 as 'iscat'
198 LEFT JOIN authorised_values ON searchcategory = authorised_value
199 WHERE searchcategory > '' and hideinopac=1
201 SELECT DISTINCT searchcategory AS `itemtype`,
202 authorised_values.lib_opac AS description,
203 authorised_values.imageurl AS imageurl,
204 hideinopac, 1 as 'iscat'
206 LEFT JOIN authorised_values ON searchcategory = authorised_value
207 WHERE searchcategory > '' and hideinopac=0
209 return ($dbh->selectall_hashref($query,'itemtype'));
212 =head2 GetItemTypesByCategory
214 @results = GetItemTypesByCategory( $searchcategory );
216 Returns the itemtype code of all itemtypes included in a searchcategory.
220 sub GetItemTypesByCategory {
224 my $dbh = C4::Context->dbh;
225 my $query = qq|SELECT itemtype FROM itemtypes WHERE searchcategory=?|;
226 my $tmp=$dbh->selectcol_arrayref($query,undef,$category);
232 $frameworks = &getframework();
234 Returns information about existing frameworks
236 build a HTML select with the following code :
238 =head3 in PERL SCRIPT
240 my $frameworks = getframeworks();
242 foreach my $thisframework (keys %$frameworks) {
243 my $selected = 1 if $thisframework eq $frameworkcode;
245 value => $thisframework,
246 selected => $selected,
247 description => $frameworks->{$thisframework}->{'frameworktext'},
249 push @frameworksloop, \%row;
251 $template->param(frameworkloop => \@frameworksloop);
255 <form action="[% script_name %] method=post>
256 <select name="frameworkcode">
257 <option value="">Default</option>
258 [% FOREACH framework IN frameworkloop %]
259 [% IF ( framework.selected ) %]
260 <option value="[% framework.value %]" selected="selected">[% framework.description %]</option>
262 <option value="[% framework.value %]">[% framework.description %]</option>
266 <input type=text name=searchfield value="[% searchfield %]">
267 <input type="submit" value="OK" class="button">
274 # returns a reference to a hash of references to branches...
276 my $dbh = C4::Context->dbh;
277 my $sth = $dbh->prepare("select * from biblio_framework");
279 while ( my $IT = $sth->fetchrow_hashref ) {
280 $itemtypes{ $IT->{'frameworkcode'} } = $IT;
282 return ( \%itemtypes );
285 =head2 getframeworkinfo
287 $frameworkinfo = &getframeworkinfo($frameworkcode);
289 Returns information about an frameworkcode.
293 sub getframeworkinfo {
294 my ($frameworkcode) = @_;
295 my $dbh = C4::Context->dbh;
297 $dbh->prepare("select * from biblio_framework where frameworkcode=?");
298 $sth->execute($frameworkcode);
299 my $res = $sth->fetchrow_hashref;
303 =head2 getitemtypeinfo
305 $itemtype = &getitemtypeinfo($itemtype, [$interface]);
307 Returns information about an itemtype. The optional $interface argument
308 sets which interface ('opac' or 'intranet') to return the imageurl for.
309 Defaults to intranet.
313 sub getitemtypeinfo {
314 my ($itemtype, $interface) = @_;
315 my $dbh = C4::Context->dbh;
316 require C4::Languages;
317 my $language = C4::Languages::getlanguage();
318 my $it = $dbh->selectrow_hashref(q|
321 itemtypes.description,
322 itemtypes.rentalcharge,
323 itemtypes.notforloan,
326 itemtypes.checkinmsg,
327 itemtypes.checkinmsgtype,
328 itemtypes.sip_media_type,
329 COALESCE( localization.translation, itemtypes.description ) AS translated_description
331 LEFT JOIN localization ON itemtypes.itemtype = localization.code
332 AND localization.entity = 'itemtypes'
333 AND localization.lang = ?
334 WHERE itemtypes.itemtype = ?
335 |, undef, $language, $itemtype );
337 $it->{imageurl} = getitemtypeimagelocation( ( ( defined $interface && $interface eq 'opac' ) ? 'opac' : 'intranet' ), $it->{imageurl} );
342 =head2 getitemtypeimagedir
344 my $directory = getitemtypeimagedir( 'opac' );
346 pass in 'opac' or 'intranet'. Defaults to 'opac'.
348 returns the full path to the appropriate directory containing images.
352 sub getitemtypeimagedir {
353 my $src = shift || 'opac';
354 if ($src eq 'intranet') {
355 return C4::Context->config('intrahtdocs') . '/' .C4::Context->preference('template') . '/img/itemtypeimg';
357 return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
361 sub getitemtypeimagesrc {
362 my $src = shift || 'opac';
363 if ($src eq 'intranet') {
364 return '/intranet-tmpl' . '/' . C4::Context->preference('template') . '/img/itemtypeimg';
366 return '/opac-tmpl' . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
370 sub getitemtypeimagelocation {
371 my ( $src, $image ) = @_;
373 return '' if ( !$image );
376 my $scheme = ( URI::Split::uri_split( $image ) )[0];
378 return $image if ( $scheme );
380 return getitemtypeimagesrc( $src ) . '/' . $image;
383 =head3 _getImagesFromDirectory
385 Find all of the image files in a directory in the filesystem
387 parameters: a directory name
389 returns: a list of images in that directory.
391 Notes: this does not traverse into subdirectories. See
392 _getSubdirectoryNames for help with that.
393 Images are assumed to be files with .gif or .png file extensions.
394 The image names returned do not have the directory name on them.
398 sub _getImagesFromDirectory {
399 my $directoryname = shift;
400 return unless defined $directoryname;
401 return unless -d $directoryname;
403 if ( opendir ( my $dh, $directoryname ) ) {
404 my @images = grep { /\.(gif|png)$/i } readdir( $dh );
406 @images = sort(@images);
409 warn "unable to opendir $directoryname: $!";
414 =head3 _getSubdirectoryNames
416 Find all of the directories in a directory in the filesystem
418 parameters: a directory name
420 returns: a list of subdirectories in that directory.
422 Notes: this does not traverse into subdirectories. Only the first
423 level of subdirectories are returned.
424 The directory names returned don't have the parent directory name on them.
428 sub _getSubdirectoryNames {
429 my $directoryname = shift;
430 return unless defined $directoryname;
431 return unless -d $directoryname;
433 if ( opendir ( my $dh, $directoryname ) ) {
434 my @directories = grep { -d File::Spec->catfile( $directoryname, $_ ) && ! ( /^\./ ) } readdir( $dh );
438 warn "unable to opendir $directoryname: $!";
445 returns: a listref of hashrefs. Each hash represents another collection of images.
447 { imagesetname => 'npl', # the name of the image set (npl is the original one)
448 images => listref of image hashrefs
451 each image is represented by a hashref like this:
453 { KohaImage => 'npl/image.gif',
454 StaffImageUrl => '/intranet-tmpl/prog/img/itemtypeimg/npl/image.gif',
455 OpacImageURL => '/opac-tmpl/prog/itemtypeimg/npl/image.gif'
456 checked => 0 or 1: was this the image passed to this method?
457 Note: I'd like to remove this somehow.
464 my $checked = $params{'checked'} || '';
466 my $paths = { staff => { filesystem => getitemtypeimagedir('intranet'),
467 url => getitemtypeimagesrc('intranet'),
469 opac => { filesystem => getitemtypeimagedir('opac'),
470 url => getitemtypeimagesrc('opac'),
474 my @imagesets = (); # list of hasrefs of image set data to pass to template
475 my @subdirectories = _getSubdirectoryNames( $paths->{'staff'}{'filesystem'} );
476 foreach my $imagesubdir ( @subdirectories ) {
477 warn $imagesubdir if $DEBUG;
478 my @imagelist = (); # hashrefs of image info
479 my @imagenames = _getImagesFromDirectory( File::Spec->catfile( $paths->{'staff'}{'filesystem'}, $imagesubdir ) );
480 my $imagesetactive = 0;
481 foreach my $thisimage ( @imagenames ) {
483 { KohaImage => "$imagesubdir/$thisimage",
484 StaffImageUrl => join( '/', $paths->{'staff'}{'url'}, $imagesubdir, $thisimage ),
485 OpacImageUrl => join( '/', $paths->{'opac'}{'url'}, $imagesubdir, $thisimage ),
486 checked => "$imagesubdir/$thisimage" eq $checked ? 1 : 0,
489 $imagesetactive = 1 if "$imagesubdir/$thisimage" eq $checked;
491 push @imagesets, { imagesetname => $imagesubdir,
492 imagesetactive => $imagesetactive,
493 images => \@imagelist };
501 $printers = &GetPrinters();
502 @queues = keys %$printers;
504 Returns information about existing printer queues.
506 C<$printers> is a reference-to-hash whose keys are the print queues
507 defined in the printers table of the Koha database. The values are
508 references-to-hash, whose keys are the fields in the printers table.
514 my $dbh = C4::Context->dbh;
515 my $sth = $dbh->prepare("select * from printers");
517 while ( my $printer = $sth->fetchrow_hashref ) {
518 $printers{ $printer->{'printqueue'} } = $printer;
520 return ( \%printers );
525 $printer = GetPrinter( $query, $printers );
530 my ( $query, $printers ) = @_; # get printer for this query from printers
531 my $printer = $query->param('printer');
532 my %cookie = $query->cookie('userenv');
533 ($printer) || ( $printer = $cookie{'printer'} ) || ( $printer = '' );
534 ( $printers->{$printer} ) || ( $printer = ( keys %$printers )[0] );
540 Returns the number of pages to display in a pagination bar, given the number
541 of items and the number of items per page.
546 my ( $nb_items, $nb_items_per_page ) = @_;
548 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
553 (@themes) = &getallthemes('opac');
554 (@themes) = &getallthemes('intranet');
556 Returns an array of all available themes.
564 if ( $type eq 'intranet' ) {
565 $htdocs = C4::Context->config('intrahtdocs');
568 $htdocs = C4::Context->config('opachtdocs');
570 opendir D, "$htdocs";
571 my @dirlist = readdir D;
572 foreach my $directory (@dirlist) {
573 next if $directory eq 'lib';
574 -d "$htdocs/$directory/en" and push @themes, $directory;
581 if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
586 tags => [ qw/ 600ab 601ab 602a 604at 605a 606ax 610a / ],
592 tags => [ qw/ 607a / ],
598 tags => [ qw/ 500a 501a 503a / ],
604 tags => [ qw/ 700ab 701ab 702ab / ],
605 sep => C4::Context->preference("UNIMARCAuthorsFacetsSeparator"),
610 tags => [ qw/ 225a / ],
616 tags => [ qw/ 995e / ],
620 unless ( Koha::Libraries->search->count == 1 )
622 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
623 if ( $DisplayLibraryFacets eq 'both'
624 || $DisplayLibraryFacets eq 'holding' )
629 idx => 'holdingbranch',
630 label => 'HoldingLibrary',
631 tags => [qw / 995c /],
636 if ( $DisplayLibraryFacets eq 'both'
637 || $DisplayLibraryFacets eq 'home' )
643 label => 'HomeLibrary',
644 tags => [qw / 995b /],
655 tags => [ qw/ 650a / ],
660 # label => 'People and Organizations',
661 # tags => [ qw/ 600a 610a 611a / ],
667 tags => [ qw/ 651a / ],
673 tags => [ qw/ 630a / ],
679 tags => [ qw/ 100a 110a 700a / ],
685 tags => [ qw/ 440a 490a / ],
690 label => 'ItemTypes',
691 tags => [ qw/ 952y 942c / ],
697 tags => [ qw / 952c / ],
701 unless ( Koha::Libraries->search->count == 1 )
703 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
704 if ( $DisplayLibraryFacets eq 'both'
705 || $DisplayLibraryFacets eq 'holding' )
710 idx => 'holdingbranch',
711 label => 'HoldingLibrary',
712 tags => [qw / 952b /],
717 if ( $DisplayLibraryFacets eq 'both'
718 || $DisplayLibraryFacets eq 'home' )
724 label => 'HomeLibrary',
725 tags => [qw / 952a /],
736 Return a href where a key is associated to a href. You give a query,
737 the name of the key among the fields returned by the query. If you
738 also give as third argument the name of the value, the function
739 returns a href of scalar. The optional 4th argument is an arrayref of
740 items passed to the C<execute()> call. It is designed to bind
741 parameters to any placeholders in your SQL.
750 # generic href of any information on the item, href of href.
751 my $iteminfos_of = get_infos_of($query, 'itemnumber');
752 print $iteminfos_of->{$itemnumber}{barcode};
754 # specific information, href of scalar
755 my $barcode_of_item = get_infos_of($query, 'itemnumber', 'barcode');
756 print $barcode_of_item->{$itemnumber};
761 my ( $query, $key_name, $value_name, $bind_params ) = @_;
763 my $dbh = C4::Context->dbh;
765 my $sth = $dbh->prepare($query);
766 $sth->execute( @$bind_params );
769 while ( my $row = $sth->fetchrow_hashref ) {
770 if ( defined $value_name ) {
771 $infos_of{ $row->{$key_name} } = $row->{$value_name};
774 $infos_of{ $row->{$key_name} } = $row;
782 =head2 get_notforloan_label_of
784 my $notforloan_label_of = get_notforloan_label_of();
786 Each authorised value of notforloan (information available in items and
787 itemtypes) is link to a single label.
789 Returns a href where keys are authorised values and values are corresponding
792 foreach my $authorised_value (keys %{$notforloan_label_of}) {
794 "authorised_value: %s => %s\n",
796 $notforloan_label_of->{$authorised_value}
802 # FIXME - why not use GetAuthorisedValues ??
804 sub get_notforloan_label_of {
805 my $dbh = C4::Context->dbh;
808 SELECT authorised_value
809 FROM marc_subfield_structure
810 WHERE kohafield = \'items.notforloan\'
813 my $sth = $dbh->prepare($query);
815 my ($statuscode) = $sth->fetchrow_array();
820 FROM authorised_values
823 $sth = $dbh->prepare($query);
824 $sth->execute($statuscode);
825 my %notforloan_label_of;
826 while ( my $row = $sth->fetchrow_hashref ) {
827 $notforloan_label_of{ $row->{authorised_value} } = $row->{lib};
831 return \%notforloan_label_of;
834 =head2 GetAuthorisedValues
836 $authvalues = GetAuthorisedValues([$category]);
838 This function returns all authorised values from the'authorised_value' table in a reference to array of hashrefs.
840 C<$category> returns authorised values for just one category (optional).
842 C<$opac> If set to a true value, displays OPAC descriptions rather than normal ones when they exist.
846 sub GetAuthorisedValues {
847 my ( $category, $opac ) = @_;
849 # Is this cached already?
850 $opac = $opac ? 1 : 0; # normalise to be safe
852 C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
854 "AuthorisedValues-$category-$opac-$branch_limit";
855 my $cache = Koha::Caches->get_instance();
856 my $result = $cache->get_from_cache($cache_key);
857 return $result if $result;
860 my $dbh = C4::Context->dbh;
863 FROM authorised_values av
866 LEFT JOIN authorised_values_branches ON ( id = av_id )
871 push @where_strings, "category = ?";
872 push @where_args, $category;
875 push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
876 push @where_args, $branch_limit;
878 if(@where_strings > 0) {
879 $query .= " WHERE " . join(" AND ", @where_strings);
881 $query .= ' ORDER BY category, ' . (
882 $opac ? 'COALESCE(lib_opac, lib)'
886 my $sth = $dbh->prepare($query);
888 $sth->execute( @where_args );
889 while (my $data=$sth->fetchrow_hashref) {
890 if ($opac && $data->{lib_opac}) {
891 $data->{lib} = $data->{lib_opac};
893 push @results, $data;
897 $cache->set_in_cache( $cache_key, \@results, { expiry => 5 } );
901 =head2 GetAuthorisedValueCategories
903 $auth_categories = GetAuthorisedValueCategories();
905 Return an arrayref of all of the available authorised
910 sub GetAuthorisedValueCategories {
911 my $dbh = C4::Context->dbh;
912 my $sth = $dbh->prepare("SELECT DISTINCT category FROM authorised_values ORDER BY category");
915 while (defined (my $category = $sth->fetchrow_array) ) {
916 push @results, $category;
923 my $escaped_string = C4::Koha::xml_escape($string);
925 Convert &, <, >, ', and " in a string to XML entities
931 return '' unless defined $str;
935 $str =~ s/'/'/g;
936 $str =~ s/"/"/g;
940 =head2 display_marc_indicators
942 my $display_form = C4::Koha::display_marc_indicators($field);
944 C<$field> is a MARC::Field object
946 Generate a display form of the indicators of a variable
947 MARC field, replacing any blanks with '#'.
951 sub display_marc_indicators {
954 if ($field && $field->tag() >= 10) {
955 $indicators = $field->indicator(1) . $field->indicator(2);
956 $indicators =~ s/ /#/g;
961 sub GetNormalizedUPC {
962 my ($marcrecord,$marcflavour) = @_;
964 return unless $marcrecord;
965 if ($marcflavour eq 'UNIMARC') {
966 my @fields = $marcrecord->field('072');
967 foreach my $field (@fields) {
968 my $upc = _normalize_match_point($field->subfield('a'));
975 else { # assume marc21 if not unimarc
976 my @fields = $marcrecord->field('024');
977 foreach my $field (@fields) {
978 my $indicator = $field->indicator(1);
979 my $upc = _normalize_match_point($field->subfield('a'));
980 if ($upc && $indicator == 1 ) {
987 # Normalizes and returns the first valid ISBN found in the record
988 # ISBN13 are converted into ISBN10. This is required to get some book cover images.
989 sub GetNormalizedISBN {
990 my ($isbn,$marcrecord,$marcflavour) = @_;
992 # Koha attempts to store multiple ISBNs in biblioitems.isbn, separated by " | "
993 # anything after " | " should be removed, along with the delimiter
994 ($isbn) = split(/\|/, $isbn );
995 return _isbn_cleanup($isbn);
998 return unless $marcrecord;
1000 if ($marcflavour eq 'UNIMARC') {
1001 my @fields = $marcrecord->field('010');
1002 foreach my $field (@fields) {
1003 my $isbn = $field->subfield('a');
1005 return _isbn_cleanup($isbn);
1009 else { # assume marc21 if not unimarc
1010 my @fields = $marcrecord->field('020');
1011 foreach my $field (@fields) {
1012 $isbn = $field->subfield('a');
1014 return _isbn_cleanup($isbn);
1020 sub GetNormalizedEAN {
1021 my ($marcrecord,$marcflavour) = @_;
1023 return unless $marcrecord;
1025 if ($marcflavour eq 'UNIMARC') {
1026 my @fields = $marcrecord->field('073');
1027 foreach my $field (@fields) {
1028 my $ean = _normalize_match_point($field->subfield('a'));
1034 else { # assume marc21 if not unimarc
1035 my @fields = $marcrecord->field('024');
1036 foreach my $field (@fields) {
1037 my $indicator = $field->indicator(1);
1038 my $ean = _normalize_match_point($field->subfield('a'));
1039 if ( $ean && $indicator == 3 ) {
1046 sub GetNormalizedOCLCNumber {
1047 my ($marcrecord,$marcflavour) = @_;
1048 return unless $marcrecord;
1050 if ($marcflavour ne 'UNIMARC' ) {
1051 my @fields = $marcrecord->field('035');
1052 foreach my $field (@fields) {
1053 my $oclc = $field->subfield('a');
1054 if ($oclc =~ /OCoLC/) {
1055 $oclc =~ s/\(OCoLC\)//;
1065 sub GetAuthvalueDropbox {
1066 my ( $authcat, $default ) = @_;
1067 my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
1068 my $dbh = C4::Context->dbh;
1072 FROM authorised_values
1075 LEFT JOIN authorised_values_branches ON ( id = av_id )
1080 $query .= " AND ( branchcode = ? OR branchcode IS NULL )" if $branch_limit;
1081 $query .= " GROUP BY lib ORDER BY category, lib, lib_opac";
1082 my $sth = $dbh->prepare($query);
1083 $sth->execute( $authcat, $branch_limit ? $branch_limit : () );
1086 my $option_list = [];
1087 my @authorised_values = ( q{} );
1088 while (my $av = $sth->fetchrow_hashref) {
1089 push @{$option_list}, {
1090 value => $av->{authorised_value},
1091 label => $av->{lib},
1092 default => ($default eq $av->{authorised_value}),
1096 if ( @{$option_list} ) {
1097 return $option_list;
1103 =head2 GetDailyQuote($opts)
1105 Takes a hashref of options
1107 Currently supported options are:
1109 'id' An exact quote id
1110 'random' Select a random quote
1111 noop When no option is passed in, this sub will return the quote timestamped for the current day
1113 The function returns an anonymous hash following this format:
1116 'source' => 'source-of-quote',
1117 'timestamp' => 'timestamp-value',
1118 'text' => 'text-of-quote',
1124 # This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
1125 # at least for default option
1129 my $dbh = C4::Context->dbh;
1134 $query = 'SELECT * FROM quotes WHERE id = ?';
1135 $sth = $dbh->prepare($query);
1136 $sth->execute($opts{'id'});
1137 $quote = $sth->fetchrow_hashref();
1139 elsif ($opts{'random'}) {
1140 # Fall through... we also return a random quote as a catch-all if all else fails
1143 $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp DESC LIMIT 0,1';
1144 $sth = $dbh->prepare($query);
1146 $quote = $sth->fetchrow_hashref();
1148 unless ($quote) { # if there are not matches, choose a random quote
1149 # get a list of all available quote ids
1150 $sth = C4::Context->dbh->prepare('SELECT count(*) FROM quotes;');
1152 my $range = ($sth->fetchrow_array)[0];
1153 # chose a random id within that range if there is more than one quote
1154 my $offset = int(rand($range));
1156 $query = 'SELECT * FROM quotes ORDER BY id LIMIT 1 OFFSET ?';
1157 $sth = C4::Context->dbh->prepare($query);
1158 # see http://www.perlmonks.org/?node_id=837422 for why
1159 # we're being verbose and using bind_param
1160 $sth->bind_param(1, $offset, SQL_INTEGER);
1162 $quote = $sth->fetchrow_hashref();
1163 # update the timestamp for that quote
1164 $query = 'UPDATE quotes SET timestamp = ? WHERE id = ?';
1165 $sth = C4::Context->dbh->prepare($query);
1167 DateTime::Format::MySQL->format_datetime( dt_from_string() ),
1174 sub _normalize_match_point {
1175 my $match_point = shift;
1176 (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
1177 $normalized_match_point =~ s/-//g;
1179 return $normalized_match_point;
1184 return NormalizeISBN(
1187 format => 'ISBN-10',
1193 =head2 NormalizedISBN
1195 my $isbns = NormalizedISBN({
1197 strip_hyphens => [0,1],
1198 format => ['ISBN-10', 'ISBN-13']
1201 Returns an isbn validated by Business::ISBN.
1202 Optionally strips hyphens and/or forces the isbn
1203 to be of the specified format.
1205 If the string cannot be validated as an isbn,
1213 my $string = $params->{isbn};
1214 my $strip_hyphens = $params->{strip_hyphens};
1215 my $format = $params->{format};
1217 return unless $string;
1219 my $isbn = Business::ISBN->new($string);
1221 if ( $isbn && $isbn->is_valid() ) {
1223 if ( $format eq 'ISBN-10' ) {
1224 $isbn = $isbn->as_isbn10();
1226 elsif ( $format eq 'ISBN-13' ) {
1227 $isbn = $isbn->as_isbn13();
1229 return unless $isbn;
1231 if ($strip_hyphens) {
1232 $string = $isbn->as_string( [] );
1234 $string = $isbn->as_string();
1241 =head2 GetVariationsOfISBN
1243 my @isbns = GetVariationsOfISBN( $isbn );
1245 Returns a list of variations of the given isbn in
1246 both ISBN-10 and ISBN-13 formats, with and without
1249 In a scalar context, the isbns are returned as a
1250 string delimited by ' | '.
1254 sub GetVariationsOfISBN {
1257 return unless $isbn;
1261 push( @isbns, NormalizeISBN({ isbn => $isbn }) );
1262 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10' }) );
1263 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13' }) );
1264 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10', strip_hyphens => 1 }) );
1265 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13', strip_hyphens => 1 }) );
1267 # Strip out any "empty" strings from the array
1268 @isbns = grep { defined($_) && $_ =~ /\S/ } @isbns;
1270 return wantarray ? @isbns : join( " | ", @isbns );
1273 =head2 GetVariationsOfISBNs
1275 my @isbns = GetVariationsOfISBNs( @isbns );
1277 Returns a list of variations of the given isbns in
1278 both ISBN-10 and ISBN-13 formats, with and without
1281 In a scalar context, the isbns are returned as a
1282 string delimited by ' | '.
1286 sub GetVariationsOfISBNs {
1289 @isbns = map { GetVariationsOfISBN( $_ ) } @isbns;
1291 return wantarray ? @isbns : join( " | ", @isbns );
1294 =head2 NormalizedISSN
1296 my $issns = NormalizedISSN({
1298 strip_hyphen => [0,1]
1301 Returns an issn validated by Business::ISSN.
1302 Optionally strips hyphen.
1304 If the string cannot be validated as an issn,
1312 my $string = $params->{issn};
1313 my $strip_hyphen = $params->{strip_hyphen};
1315 my $issn = Business::ISSN->new($string);
1317 if ( $issn && $issn->is_valid ){
1319 if ($strip_hyphen) {
1320 $string = $issn->_issn;
1323 $string = $issn->as_string;
1330 =head2 GetVariationsOfISSN
1332 my @issns = GetVariationsOfISSN( $issn );
1334 Returns a list of variations of the given issn in
1335 with and without a hyphen.
1337 In a scalar context, the issns are returned as a
1338 string delimited by ' | '.
1342 sub GetVariationsOfISSN {
1345 return unless $issn;
1348 my $str = NormalizeISSN({ issn => $issn });
1351 push @issns, NormalizeISSN({ issn => $issn, strip_hyphen => 1 });
1356 # Strip out any "empty" strings from the array
1357 @issns = grep { defined($_) && $_ =~ /\S/ } @issns;
1359 return wantarray ? @issns : join( " | ", @issns );
1362 =head2 GetVariationsOfISSNs
1364 my @issns = GetVariationsOfISSNs( @issns );
1366 Returns a list of variations of the given issns in
1367 with and without a hyphen.
1369 In a scalar context, the issns are returned as a
1370 string delimited by ' | '.
1374 sub GetVariationsOfISSNs {
1377 @issns = map { GetVariationsOfISSN( $_ ) } @issns;
1379 return wantarray ? @issns : join( " | ", @issns );
1383 =head2 IsKohaFieldLinked
1385 my $is_linked = IsKohaFieldLinked({
1386 kohafield => $kohafield,
1387 frameworkcode => $frameworkcode,
1390 Return 1 if the field is linked
1394 sub IsKohaFieldLinked {
1395 my ( $params ) = @_;
1396 my $kohafield = $params->{kohafield};
1397 my $frameworkcode = $params->{frameworkcode} || '';
1398 my $dbh = C4::Context->dbh;
1399 my $is_linked = $dbh->selectcol_arrayref( q|
1401 FROM marc_subfield_structure
1402 WHERE frameworkcode = ?
1404 |,{}, $frameworkcode, $kohafield );
1405 return $is_linked->[0];