Bug 9302: Use patron-title.inc
[koha.git] / C4 / Koha.pm
blob42c8af1d281d39a03e330b862acc6bacaae024e4
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 Koha::Caches;
28 use Koha::DateUtils qw(dt_from_string);
29 use Koha::AuthorisedValues;
30 use Koha::Libraries;
31 use Koha::MarcSubfieldStructures;
32 use DateTime::Format::MySQL;
33 use Business::ISBN;
34 use Business::ISSN;
35 use autouse 'Data::cselectall_arrayref' => qw(Dumper);
36 use DBI qw(:sql_types);
37 use vars qw(@ISA @EXPORT @EXPORT_OK $DEBUG);
39 BEGIN {
40 require Exporter;
41 @ISA = qw(Exporter);
42 @EXPORT = qw(
43 &GetPrinters &GetPrinter
44 &GetItemTypesCategorized
45 &getallthemes
46 &getFacets
47 &getnbpages
48 &getitemtypeimagedir
49 &getitemtypeimagesrc
50 &getitemtypeimagelocation
51 &GetAuthorisedValues
52 &GetNormalizedUPC
53 &GetNormalizedISBN
54 &GetNormalizedEAN
55 &GetNormalizedOCLCNumber
56 &xml_escape
58 &GetVariationsOfISBN
59 &GetVariationsOfISBNs
60 &NormalizeISBN
61 &GetVariationsOfISSN
62 &GetVariationsOfISSNs
63 &NormalizeISSN
65 $DEBUG
67 $DEBUG = 0;
68 @EXPORT_OK = qw( GetDailyQuote );
71 =head1 NAME
73 C4::Koha - Perl Module containing convenience functions for Koha scripts
75 =head1 SYNOPSIS
77 use C4::Koha;
79 =head1 DESCRIPTION
81 Koha.pm provides many functions for Koha scripts.
83 =head1 FUNCTIONS
85 =cut
87 =head2 GetItemTypesCategorized
89 $categories = GetItemTypesCategorized();
91 Returns a hashref containing search categories.
92 A search category will be put in the hash if at least one of its itemtypes is visible in OPAC.
93 The categories must be part of Authorized Values (ITEMTYPECAT)
95 =cut
97 sub GetItemTypesCategorized {
98 my $dbh = C4::Context->dbh;
99 # Order is important, so that partially hidden (some items are not visible in OPAC) search
100 # categories will be visible. hideinopac=0 must be last.
101 my $query = q|
102 SELECT itemtype, description, imageurl, hideinopac, 0 as 'iscat' FROM itemtypes WHERE ISNULL(searchcategory) or length(searchcategory) = 0
103 UNION
104 SELECT DISTINCT searchcategory AS `itemtype`,
105 authorised_values.lib_opac AS description,
106 authorised_values.imageurl AS imageurl,
107 hideinopac, 1 as 'iscat'
108 FROM itemtypes
109 LEFT JOIN authorised_values ON searchcategory = authorised_value
110 WHERE searchcategory > '' and hideinopac=1
111 UNION
112 SELECT DISTINCT searchcategory AS `itemtype`,
113 authorised_values.lib_opac AS description,
114 authorised_values.imageurl AS imageurl,
115 hideinopac, 1 as 'iscat'
116 FROM itemtypes
117 LEFT JOIN authorised_values ON searchcategory = authorised_value
118 WHERE searchcategory > '' and hideinopac=0
120 return ($dbh->selectall_hashref($query,'itemtype'));
123 =head2 getitemtypeimagedir
125 my $directory = getitemtypeimagedir( 'opac' );
127 pass in 'opac' or 'intranet'. Defaults to 'opac'.
129 returns the full path to the appropriate directory containing images.
131 =cut
133 sub getitemtypeimagedir {
134 my $src = shift || 'opac';
135 if ($src eq 'intranet') {
136 return C4::Context->config('intrahtdocs') . '/' .C4::Context->preference('template') . '/img/itemtypeimg';
137 } else {
138 return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
142 sub getitemtypeimagesrc {
143 my $src = shift || 'opac';
144 if ($src eq 'intranet') {
145 return '/intranet-tmpl' . '/' . C4::Context->preference('template') . '/img/itemtypeimg';
146 } else {
147 return '/opac-tmpl' . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
151 sub getitemtypeimagelocation {
152 my ( $src, $image ) = @_;
154 return '' if ( !$image );
155 require URI::Split;
157 my $scheme = ( URI::Split::uri_split( $image ) )[0];
159 return $image if ( $scheme );
161 return getitemtypeimagesrc( $src ) . '/' . $image;
164 =head3 _getImagesFromDirectory
166 Find all of the image files in a directory in the filesystem
168 parameters: a directory name
170 returns: a list of images in that directory.
172 Notes: this does not traverse into subdirectories. See
173 _getSubdirectoryNames for help with that.
174 Images are assumed to be files with .gif or .png file extensions.
175 The image names returned do not have the directory name on them.
177 =cut
179 sub _getImagesFromDirectory {
180 my $directoryname = shift;
181 return unless defined $directoryname;
182 return unless -d $directoryname;
184 if ( opendir ( my $dh, $directoryname ) ) {
185 my @images = grep { /\.(gif|png)$/i } readdir( $dh );
186 closedir $dh;
187 @images = sort(@images);
188 return @images;
189 } else {
190 warn "unable to opendir $directoryname: $!";
191 return;
195 =head3 _getSubdirectoryNames
197 Find all of the directories in a directory in the filesystem
199 parameters: a directory name
201 returns: a list of subdirectories in that directory.
203 Notes: this does not traverse into subdirectories. Only the first
204 level of subdirectories are returned.
205 The directory names returned don't have the parent directory name on them.
207 =cut
209 sub _getSubdirectoryNames {
210 my $directoryname = shift;
211 return unless defined $directoryname;
212 return unless -d $directoryname;
214 if ( opendir ( my $dh, $directoryname ) ) {
215 my @directories = grep { -d File::Spec->catfile( $directoryname, $_ ) && ! ( /^\./ ) } readdir( $dh );
216 closedir $dh;
217 return @directories;
218 } else {
219 warn "unable to opendir $directoryname: $!";
220 return;
224 =head3 getImageSets
226 returns: a listref of hashrefs. Each hash represents another collection of images.
228 { imagesetname => 'npl', # the name of the image set (npl is the original one)
229 images => listref of image hashrefs
232 each image is represented by a hashref like this:
234 { KohaImage => 'npl/image.gif',
235 StaffImageUrl => '/intranet-tmpl/prog/img/itemtypeimg/npl/image.gif',
236 OpacImageURL => '/opac-tmpl/prog/itemtypeimg/npl/image.gif'
237 checked => 0 or 1: was this the image passed to this method?
238 Note: I'd like to remove this somehow.
241 =cut
243 sub getImageSets {
244 my %params = @_;
245 my $checked = $params{'checked'} || '';
247 my $paths = { staff => { filesystem => getitemtypeimagedir('intranet'),
248 url => getitemtypeimagesrc('intranet'),
250 opac => { filesystem => getitemtypeimagedir('opac'),
251 url => getitemtypeimagesrc('opac'),
255 my @imagesets = (); # list of hasrefs of image set data to pass to template
256 my @subdirectories = _getSubdirectoryNames( $paths->{'staff'}{'filesystem'} );
257 foreach my $imagesubdir ( @subdirectories ) {
258 warn $imagesubdir if $DEBUG;
259 my @imagelist = (); # hashrefs of image info
260 my @imagenames = _getImagesFromDirectory( File::Spec->catfile( $paths->{'staff'}{'filesystem'}, $imagesubdir ) );
261 my $imagesetactive = 0;
262 foreach my $thisimage ( @imagenames ) {
263 push( @imagelist,
264 { KohaImage => "$imagesubdir/$thisimage",
265 StaffImageUrl => join( '/', $paths->{'staff'}{'url'}, $imagesubdir, $thisimage ),
266 OpacImageUrl => join( '/', $paths->{'opac'}{'url'}, $imagesubdir, $thisimage ),
267 checked => "$imagesubdir/$thisimage" eq $checked ? 1 : 0,
270 $imagesetactive = 1 if "$imagesubdir/$thisimage" eq $checked;
272 push @imagesets, { imagesetname => $imagesubdir,
273 imagesetactive => $imagesetactive,
274 images => \@imagelist };
277 return \@imagesets;
280 =head2 GetPrinters
282 $printers = &GetPrinters();
283 @queues = keys %$printers;
285 Returns information about existing printer queues.
287 C<$printers> is a reference-to-hash whose keys are the print queues
288 defined in the printers table of the Koha database. The values are
289 references-to-hash, whose keys are the fields in the printers table.
291 =cut
293 sub GetPrinters {
294 my %printers;
295 my $dbh = C4::Context->dbh;
296 my $sth = $dbh->prepare("select * from printers");
297 $sth->execute;
298 while ( my $printer = $sth->fetchrow_hashref ) {
299 $printers{ $printer->{'printqueue'} } = $printer;
301 return ( \%printers );
304 =head2 GetPrinter
306 $printer = GetPrinter( $query, $printers );
308 =cut
310 sub GetPrinter {
311 my ( $query, $printers ) = @_; # get printer for this query from printers
312 my $printer = $query->param('printer');
313 my %cookie = $query->cookie('userenv');
314 ($printer) || ( $printer = $cookie{'printer'} ) || ( $printer = '' );
315 ( $printers->{$printer} ) || ( $printer = ( keys %$printers )[0] );
316 return $printer;
319 =head2 getnbpages
321 Returns the number of pages to display in a pagination bar, given the number
322 of items and the number of items per page.
324 =cut
326 sub getnbpages {
327 my ( $nb_items, $nb_items_per_page ) = @_;
329 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
332 =head2 getallthemes
334 (@themes) = &getallthemes('opac');
335 (@themes) = &getallthemes('intranet');
337 Returns an array of all available themes.
339 =cut
341 sub getallthemes {
342 my $type = shift;
343 my $htdocs;
344 my @themes;
345 if ( $type eq 'intranet' ) {
346 $htdocs = C4::Context->config('intrahtdocs');
348 else {
349 $htdocs = C4::Context->config('opachtdocs');
351 opendir D, "$htdocs";
352 my @dirlist = readdir D;
353 foreach my $directory (@dirlist) {
354 next if $directory eq 'lib';
355 -d "$htdocs/$directory/en" and push @themes, $directory;
357 return @themes;
360 sub getFacets {
361 my $facets;
362 if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
363 $facets = [
365 idx => 'su-to',
366 label => 'Topics',
367 tags => [ qw/ 600ab 601ab 602a 604at 605a 606ax 610a / ],
368 sep => ' - ',
371 idx => 'su-geo',
372 label => 'Places',
373 tags => [ qw/ 607a / ],
374 sep => ' - ',
377 idx => 'su-ut',
378 label => 'Titles',
379 tags => [ qw/ 500a 501a 503a / ],
380 sep => ', ',
383 idx => 'au',
384 label => 'Authors',
385 tags => [ qw/ 700ab 701ab 702ab / ],
386 sep => C4::Context->preference("UNIMARCAuthorsFacetsSeparator"),
389 idx => 'se',
390 label => 'Series',
391 tags => [ qw/ 225a / ],
392 sep => ', ',
395 idx => 'location',
396 label => 'Location',
397 tags => [ qw/ 995e / ],
401 unless ( Koha::Libraries->search->count == 1 )
403 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
404 if ( $DisplayLibraryFacets eq 'both'
405 || $DisplayLibraryFacets eq 'holding' )
407 push(
408 @$facets,
410 idx => 'holdingbranch',
411 label => 'HoldingLibrary',
412 tags => [qw / 995c /],
417 if ( $DisplayLibraryFacets eq 'both'
418 || $DisplayLibraryFacets eq 'home' )
420 push(
421 @$facets,
423 idx => 'homebranch',
424 label => 'HomeLibrary',
425 tags => [qw / 995b /],
431 else {
432 $facets = [
434 idx => 'su-to',
435 label => 'Topics',
436 tags => [ qw/ 650a / ],
437 sep => '--',
440 # idx => 'su-na',
441 # label => 'People and Organizations',
442 # tags => [ qw/ 600a 610a 611a / ],
443 # sep => 'a',
444 # },
446 idx => 'su-geo',
447 label => 'Places',
448 tags => [ qw/ 651a / ],
449 sep => '--',
452 idx => 'su-ut',
453 label => 'Titles',
454 tags => [ qw/ 630a / ],
455 sep => '--',
458 idx => 'au',
459 label => 'Authors',
460 tags => [ qw/ 100a 110a 700a / ],
461 sep => ', ',
464 idx => 'se',
465 label => 'Series',
466 tags => [ qw/ 440a 490a / ],
467 sep => ', ',
470 idx => 'itype',
471 label => 'ItemTypes',
472 tags => [ qw/ 952y 942c / ],
473 sep => ', ',
476 idx => 'location',
477 label => 'Location',
478 tags => [ qw / 952c / ],
482 unless ( Koha::Libraries->search->count == 1 )
484 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
485 if ( $DisplayLibraryFacets eq 'both'
486 || $DisplayLibraryFacets eq 'holding' )
488 push(
489 @$facets,
491 idx => 'holdingbranch',
492 label => 'HoldingLibrary',
493 tags => [qw / 952b /],
498 if ( $DisplayLibraryFacets eq 'both'
499 || $DisplayLibraryFacets eq 'home' )
501 push(
502 @$facets,
504 idx => 'homebranch',
505 label => 'HomeLibrary',
506 tags => [qw / 952a /],
512 return $facets;
515 =head2 GetAuthorisedValues
517 $authvalues = GetAuthorisedValues([$category]);
519 This function returns all authorised values from the'authorised_value' table in a reference to array of hashrefs.
521 C<$category> returns authorised values for just one category (optional).
523 C<$opac> If set to a true value, displays OPAC descriptions rather than normal ones when they exist.
525 =cut
527 sub GetAuthorisedValues {
528 my ( $category, $opac ) = @_;
530 # Is this cached already?
531 $opac = $opac ? 1 : 0; # normalise to be safe
532 my $branch_limit =
533 C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
534 my $cache_key =
535 "AuthorisedValues-$category-$opac-$branch_limit";
536 my $cache = Koha::Caches->get_instance();
537 my $result = $cache->get_from_cache($cache_key);
538 return $result if $result;
540 my @results;
541 my $dbh = C4::Context->dbh;
542 my $query = qq{
543 SELECT DISTINCT av.*
544 FROM authorised_values av
546 $query .= qq{
547 LEFT JOIN authorised_values_branches ON ( id = av_id )
548 } if $branch_limit;
549 my @where_strings;
550 my @where_args;
551 if($category) {
552 push @where_strings, "category = ?";
553 push @where_args, $category;
555 if($branch_limit) {
556 push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
557 push @where_args, $branch_limit;
559 if(@where_strings > 0) {
560 $query .= " WHERE " . join(" AND ", @where_strings);
562 $query .= ' ORDER BY category, ' . (
563 $opac ? 'COALESCE(lib_opac, lib)'
564 : 'lib, lib_opac'
567 my $sth = $dbh->prepare($query);
569 $sth->execute( @where_args );
570 while (my $data=$sth->fetchrow_hashref) {
571 if ($opac && $data->{lib_opac}) {
572 $data->{lib} = $data->{lib_opac};
574 push @results, $data;
576 $sth->finish;
578 $cache->set_in_cache( $cache_key, \@results, { expiry => 5 } );
579 return \@results;
582 =head2 xml_escape
584 my $escaped_string = C4::Koha::xml_escape($string);
586 Convert &, <, >, ', and " in a string to XML entities
588 =cut
590 sub xml_escape {
591 my $str = shift;
592 return '' unless defined $str;
593 $str =~ s/&/&amp;/g;
594 $str =~ s/</&lt;/g;
595 $str =~ s/>/&gt;/g;
596 $str =~ s/'/&apos;/g;
597 $str =~ s/"/&quot;/g;
598 return $str;
601 =head2 display_marc_indicators
603 my $display_form = C4::Koha::display_marc_indicators($field);
605 C<$field> is a MARC::Field object
607 Generate a display form of the indicators of a variable
608 MARC field, replacing any blanks with '#'.
610 =cut
612 sub display_marc_indicators {
613 my $field = shift;
614 my $indicators = '';
615 if ($field && $field->tag() >= 10) {
616 $indicators = $field->indicator(1) . $field->indicator(2);
617 $indicators =~ s/ /#/g;
619 return $indicators;
622 sub GetNormalizedUPC {
623 my ($marcrecord,$marcflavour) = @_;
625 return unless $marcrecord;
626 if ($marcflavour eq 'UNIMARC') {
627 my @fields = $marcrecord->field('072');
628 foreach my $field (@fields) {
629 my $upc = _normalize_match_point($field->subfield('a'));
630 if ($upc) {
631 return $upc;
636 else { # assume marc21 if not unimarc
637 my @fields = $marcrecord->field('024');
638 foreach my $field (@fields) {
639 my $indicator = $field->indicator(1);
640 my $upc = _normalize_match_point($field->subfield('a'));
641 if ($upc && $indicator == 1 ) {
642 return $upc;
648 # Normalizes and returns the first valid ISBN found in the record
649 # ISBN13 are converted into ISBN10. This is required to get some book cover images.
650 sub GetNormalizedISBN {
651 my ($isbn,$marcrecord,$marcflavour) = @_;
652 if ($isbn) {
653 # Koha attempts to store multiple ISBNs in biblioitems.isbn, separated by " | "
654 # anything after " | " should be removed, along with the delimiter
655 ($isbn) = split(/\|/, $isbn );
656 return _isbn_cleanup($isbn);
659 return unless $marcrecord;
661 if ($marcflavour eq 'UNIMARC') {
662 my @fields = $marcrecord->field('010');
663 foreach my $field (@fields) {
664 my $isbn = $field->subfield('a');
665 if ($isbn) {
666 return _isbn_cleanup($isbn);
670 else { # assume marc21 if not unimarc
671 my @fields = $marcrecord->field('020');
672 foreach my $field (@fields) {
673 $isbn = $field->subfield('a');
674 if ($isbn) {
675 return _isbn_cleanup($isbn);
681 sub GetNormalizedEAN {
682 my ($marcrecord,$marcflavour) = @_;
684 return unless $marcrecord;
686 if ($marcflavour eq 'UNIMARC') {
687 my @fields = $marcrecord->field('073');
688 foreach my $field (@fields) {
689 my $ean = _normalize_match_point($field->subfield('a'));
690 if ( $ean ) {
691 return $ean;
695 else { # assume marc21 if not unimarc
696 my @fields = $marcrecord->field('024');
697 foreach my $field (@fields) {
698 my $indicator = $field->indicator(1);
699 my $ean = _normalize_match_point($field->subfield('a'));
700 if ( $ean && $indicator == 3 ) {
701 return $ean;
707 sub GetNormalizedOCLCNumber {
708 my ($marcrecord,$marcflavour) = @_;
709 return unless $marcrecord;
711 if ($marcflavour ne 'UNIMARC' ) {
712 my @fields = $marcrecord->field('035');
713 foreach my $field (@fields) {
714 my $oclc = $field->subfield('a');
715 if ($oclc =~ /OCoLC/) {
716 $oclc =~ s/\(OCoLC\)//;
717 return $oclc;
720 } else {
721 # TODO for UNIMARC
723 return
726 =head2 GetDailyQuote($opts)
728 Takes a hashref of options
730 Currently supported options are:
732 'id' An exact quote id
733 'random' Select a random quote
734 noop When no option is passed in, this sub will return the quote timestamped for the current day
736 The function returns an anonymous hash following this format:
739 'source' => 'source-of-quote',
740 'timestamp' => 'timestamp-value',
741 'text' => 'text-of-quote',
742 'id' => 'quote-id'
745 =cut
747 # This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
748 # at least for default option
750 sub GetDailyQuote {
751 my %opts = @_;
752 my $dbh = C4::Context->dbh;
753 my $query = '';
754 my $sth = undef;
755 my $quote = undef;
756 if ($opts{'id'}) {
757 $query = 'SELECT * FROM quotes WHERE id = ?';
758 $sth = $dbh->prepare($query);
759 $sth->execute($opts{'id'});
760 $quote = $sth->fetchrow_hashref();
762 elsif ($opts{'random'}) {
763 # Fall through... we also return a random quote as a catch-all if all else fails
765 else {
766 $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp DESC LIMIT 0,1';
767 $sth = $dbh->prepare($query);
768 $sth->execute();
769 $quote = $sth->fetchrow_hashref();
771 unless ($quote) { # if there are not matches, choose a random quote
772 # get a list of all available quote ids
773 $sth = C4::Context->dbh->prepare('SELECT count(*) FROM quotes;');
774 $sth->execute;
775 my $range = ($sth->fetchrow_array)[0];
776 # chose a random id within that range if there is more than one quote
777 my $offset = int(rand($range));
778 # grab it
779 $query = 'SELECT * FROM quotes ORDER BY id LIMIT 1 OFFSET ?';
780 $sth = C4::Context->dbh->prepare($query);
781 # see http://www.perlmonks.org/?node_id=837422 for why
782 # we're being verbose and using bind_param
783 $sth->bind_param(1, $offset, SQL_INTEGER);
784 $sth->execute();
785 $quote = $sth->fetchrow_hashref();
786 # update the timestamp for that quote
787 $query = 'UPDATE quotes SET timestamp = ? WHERE id = ?';
788 $sth = C4::Context->dbh->prepare($query);
789 $sth->execute(
790 DateTime::Format::MySQL->format_datetime( dt_from_string() ),
791 $quote->{'id'}
794 return $quote;
797 sub _normalize_match_point {
798 my $match_point = shift;
799 (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
800 $normalized_match_point =~ s/-//g;
802 return $normalized_match_point;
805 sub _isbn_cleanup {
806 my ($isbn) = @_;
807 return NormalizeISBN(
809 isbn => $isbn,
810 format => 'ISBN-10',
811 strip_hyphens => 1,
813 ) if $isbn;
816 =head2 NormalizedISBN
818 my $isbns = NormalizedISBN({
819 isbn => $isbn,
820 strip_hyphens => [0,1],
821 format => ['ISBN-10', 'ISBN-13']
824 Returns an isbn validated by Business::ISBN.
825 Optionally strips hyphens and/or forces the isbn
826 to be of the specified format.
828 If the string cannot be validated as an isbn,
829 it returns nothing.
831 =cut
833 sub NormalizeISBN {
834 my ($params) = @_;
836 my $string = $params->{isbn};
837 my $strip_hyphens = $params->{strip_hyphens};
838 my $format = $params->{format};
840 return unless $string;
842 my $isbn = Business::ISBN->new($string);
844 if ( $isbn && $isbn->is_valid() ) {
846 if ( $format eq 'ISBN-10' ) {
847 $isbn = $isbn->as_isbn10();
849 elsif ( $format eq 'ISBN-13' ) {
850 $isbn = $isbn->as_isbn13();
852 return unless $isbn;
854 if ($strip_hyphens) {
855 $string = $isbn->as_string( [] );
856 } else {
857 $string = $isbn->as_string();
860 return $string;
864 =head2 GetVariationsOfISBN
866 my @isbns = GetVariationsOfISBN( $isbn );
868 Returns a list of variations of the given isbn in
869 both ISBN-10 and ISBN-13 formats, with and without
870 hyphens.
872 In a scalar context, the isbns are returned as a
873 string delimited by ' | '.
875 =cut
877 sub GetVariationsOfISBN {
878 my ($isbn) = @_;
880 return unless $isbn;
882 my @isbns;
884 push( @isbns, NormalizeISBN({ isbn => $isbn }) );
885 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10' }) );
886 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13' }) );
887 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10', strip_hyphens => 1 }) );
888 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13', strip_hyphens => 1 }) );
890 # Strip out any "empty" strings from the array
891 @isbns = grep { defined($_) && $_ =~ /\S/ } @isbns;
893 return wantarray ? @isbns : join( " | ", @isbns );
896 =head2 GetVariationsOfISBNs
898 my @isbns = GetVariationsOfISBNs( @isbns );
900 Returns a list of variations of the given isbns in
901 both ISBN-10 and ISBN-13 formats, with and without
902 hyphens.
904 In a scalar context, the isbns are returned as a
905 string delimited by ' | '.
907 =cut
909 sub GetVariationsOfISBNs {
910 my (@isbns) = @_;
912 @isbns = map { GetVariationsOfISBN( $_ ) } @isbns;
914 return wantarray ? @isbns : join( " | ", @isbns );
917 =head2 NormalizedISSN
919 my $issns = NormalizedISSN({
920 issn => $issn,
921 strip_hyphen => [0,1]
924 Returns an issn validated by Business::ISSN.
925 Optionally strips hyphen.
927 If the string cannot be validated as an issn,
928 it returns nothing.
930 =cut
932 sub NormalizeISSN {
933 my ($params) = @_;
935 my $string = $params->{issn};
936 my $strip_hyphen = $params->{strip_hyphen};
938 my $issn = Business::ISSN->new($string);
940 if ( $issn && $issn->is_valid ){
942 if ($strip_hyphen) {
943 $string = $issn->_issn;
945 else {
946 $string = $issn->as_string;
948 return $string;
953 =head2 GetVariationsOfISSN
955 my @issns = GetVariationsOfISSN( $issn );
957 Returns a list of variations of the given issn in
958 with and without a hyphen.
960 In a scalar context, the issns are returned as a
961 string delimited by ' | '.
963 =cut
965 sub GetVariationsOfISSN {
966 my ( $issn ) = @_;
968 return unless $issn;
970 my @issns;
971 my $str = NormalizeISSN({ issn => $issn });
972 if( $str ) {
973 push @issns, $str;
974 push @issns, NormalizeISSN({ issn => $issn, strip_hyphen => 1 });
975 } else {
976 push @issns, $issn;
979 # Strip out any "empty" strings from the array
980 @issns = grep { defined($_) && $_ =~ /\S/ } @issns;
982 return wantarray ? @issns : join( " | ", @issns );
985 =head2 GetVariationsOfISSNs
987 my @issns = GetVariationsOfISSNs( @issns );
989 Returns a list of variations of the given issns in
990 with and without a hyphen.
992 In a scalar context, the issns are returned as a
993 string delimited by ' | '.
995 =cut
997 sub GetVariationsOfISSNs {
998 my (@issns) = @_;
1000 @issns = map { GetVariationsOfISSN( $_ ) } @issns;
1002 return wantarray ? @issns : join( " | ", @issns );
1007 __END__
1009 =head1 AUTHOR
1011 Koha Team
1013 =cut