Bug 18182: Make TestBuilder capable of returning Koha::Object
[koha.git] / C4 / Koha.pm
blob6932293887b70c1b3cbf0a0850493b60daf6779a
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 &getitemtypeinfo
45 &GetItemTypesCategorized
46 &getallthemes
47 &getFacets
48 &getnbpages
49 &getitemtypeimagedir
50 &getitemtypeimagesrc
51 &getitemtypeimagelocation
52 &GetAuthorisedValues
53 &GetNormalizedUPC
54 &GetNormalizedISBN
55 &GetNormalizedEAN
56 &GetNormalizedOCLCNumber
57 &xml_escape
59 &GetVariationsOfISBN
60 &GetVariationsOfISBNs
61 &NormalizeISBN
62 &GetVariationsOfISSN
63 &GetVariationsOfISSNs
64 &NormalizeISSN
66 $DEBUG
68 $DEBUG = 0;
69 @EXPORT_OK = qw( GetDailyQuote );
72 =head1 NAME
74 C4::Koha - Perl Module containing convenience functions for Koha scripts
76 =head1 SYNOPSIS
78 use C4::Koha;
80 =head1 DESCRIPTION
82 Koha.pm provides many functions for Koha scripts.
84 =head1 FUNCTIONS
86 =cut
88 =head2 GetItemTypesCategorized
90 $categories = GetItemTypesCategorized();
92 Returns a hashref containing search categories.
93 A search category will be put in the hash if at least one of its itemtypes is visible in OPAC.
94 The categories must be part of Authorized Values (ITEMTYPECAT)
96 =cut
98 sub GetItemTypesCategorized {
99 my $dbh = C4::Context->dbh;
100 # Order is important, so that partially hidden (some items are not visible in OPAC) search
101 # categories will be visible. hideinopac=0 must be last.
102 my $query = q|
103 SELECT itemtype, description, imageurl, hideinopac, 0 as 'iscat' FROM itemtypes WHERE ISNULL(searchcategory) or length(searchcategory) = 0
104 UNION
105 SELECT DISTINCT searchcategory AS `itemtype`,
106 authorised_values.lib_opac AS description,
107 authorised_values.imageurl AS imageurl,
108 hideinopac, 1 as 'iscat'
109 FROM itemtypes
110 LEFT JOIN authorised_values ON searchcategory = authorised_value
111 WHERE searchcategory > '' and hideinopac=1
112 UNION
113 SELECT DISTINCT searchcategory AS `itemtype`,
114 authorised_values.lib_opac AS description,
115 authorised_values.imageurl AS imageurl,
116 hideinopac, 1 as 'iscat'
117 FROM itemtypes
118 LEFT JOIN authorised_values ON searchcategory = authorised_value
119 WHERE searchcategory > '' and hideinopac=0
121 return ($dbh->selectall_hashref($query,'itemtype'));
124 =head2 getitemtypeinfo
126 $itemtype = &getitemtypeinfo($itemtype, [$interface]);
128 Returns information about an itemtype. The optional $interface argument
129 sets which interface ('opac' or 'intranet') to return the imageurl for.
130 Defaults to intranet.
132 =cut
134 sub getitemtypeinfo {
135 my ($itemtype, $interface) = @_;
136 my $dbh = C4::Context->dbh;
137 require C4::Languages;
138 my $language = C4::Languages::getlanguage();
139 my $it = $dbh->selectrow_hashref(q|
140 SELECT
141 itemtypes.itemtype,
142 itemtypes.description,
143 itemtypes.rentalcharge,
144 itemtypes.notforloan,
145 itemtypes.imageurl,
146 itemtypes.summary,
147 itemtypes.checkinmsg,
148 itemtypes.checkinmsgtype,
149 itemtypes.sip_media_type,
150 COALESCE( localization.translation, itemtypes.description ) AS translated_description
151 FROM itemtypes
152 LEFT JOIN localization ON itemtypes.itemtype = localization.code
153 AND localization.entity = 'itemtypes'
154 AND localization.lang = ?
155 WHERE itemtypes.itemtype = ?
156 |, undef, $language, $itemtype );
158 $it->{imageurl} = getitemtypeimagelocation( ( ( defined $interface && $interface eq 'opac' ) ? 'opac' : 'intranet' ), $it->{imageurl} );
160 return $it;
163 =head2 getitemtypeimagedir
165 my $directory = getitemtypeimagedir( 'opac' );
167 pass in 'opac' or 'intranet'. Defaults to 'opac'.
169 returns the full path to the appropriate directory containing images.
171 =cut
173 sub getitemtypeimagedir {
174 my $src = shift || 'opac';
175 if ($src eq 'intranet') {
176 return C4::Context->config('intrahtdocs') . '/' .C4::Context->preference('template') . '/img/itemtypeimg';
177 } else {
178 return C4::Context->config('opachtdocs') . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
182 sub getitemtypeimagesrc {
183 my $src = shift || 'opac';
184 if ($src eq 'intranet') {
185 return '/intranet-tmpl' . '/' . C4::Context->preference('template') . '/img/itemtypeimg';
186 } else {
187 return '/opac-tmpl' . '/' . C4::Context->preference('opacthemes') . '/itemtypeimg';
191 sub getitemtypeimagelocation {
192 my ( $src, $image ) = @_;
194 return '' if ( !$image );
195 require URI::Split;
197 my $scheme = ( URI::Split::uri_split( $image ) )[0];
199 return $image if ( $scheme );
201 return getitemtypeimagesrc( $src ) . '/' . $image;
204 =head3 _getImagesFromDirectory
206 Find all of the image files in a directory in the filesystem
208 parameters: a directory name
210 returns: a list of images in that directory.
212 Notes: this does not traverse into subdirectories. See
213 _getSubdirectoryNames for help with that.
214 Images are assumed to be files with .gif or .png file extensions.
215 The image names returned do not have the directory name on them.
217 =cut
219 sub _getImagesFromDirectory {
220 my $directoryname = shift;
221 return unless defined $directoryname;
222 return unless -d $directoryname;
224 if ( opendir ( my $dh, $directoryname ) ) {
225 my @images = grep { /\.(gif|png)$/i } readdir( $dh );
226 closedir $dh;
227 @images = sort(@images);
228 return @images;
229 } else {
230 warn "unable to opendir $directoryname: $!";
231 return;
235 =head3 _getSubdirectoryNames
237 Find all of the directories in a directory in the filesystem
239 parameters: a directory name
241 returns: a list of subdirectories in that directory.
243 Notes: this does not traverse into subdirectories. Only the first
244 level of subdirectories are returned.
245 The directory names returned don't have the parent directory name on them.
247 =cut
249 sub _getSubdirectoryNames {
250 my $directoryname = shift;
251 return unless defined $directoryname;
252 return unless -d $directoryname;
254 if ( opendir ( my $dh, $directoryname ) ) {
255 my @directories = grep { -d File::Spec->catfile( $directoryname, $_ ) && ! ( /^\./ ) } readdir( $dh );
256 closedir $dh;
257 return @directories;
258 } else {
259 warn "unable to opendir $directoryname: $!";
260 return;
264 =head3 getImageSets
266 returns: a listref of hashrefs. Each hash represents another collection of images.
268 { imagesetname => 'npl', # the name of the image set (npl is the original one)
269 images => listref of image hashrefs
272 each image is represented by a hashref like this:
274 { KohaImage => 'npl/image.gif',
275 StaffImageUrl => '/intranet-tmpl/prog/img/itemtypeimg/npl/image.gif',
276 OpacImageURL => '/opac-tmpl/prog/itemtypeimg/npl/image.gif'
277 checked => 0 or 1: was this the image passed to this method?
278 Note: I'd like to remove this somehow.
281 =cut
283 sub getImageSets {
284 my %params = @_;
285 my $checked = $params{'checked'} || '';
287 my $paths = { staff => { filesystem => getitemtypeimagedir('intranet'),
288 url => getitemtypeimagesrc('intranet'),
290 opac => { filesystem => getitemtypeimagedir('opac'),
291 url => getitemtypeimagesrc('opac'),
295 my @imagesets = (); # list of hasrefs of image set data to pass to template
296 my @subdirectories = _getSubdirectoryNames( $paths->{'staff'}{'filesystem'} );
297 foreach my $imagesubdir ( @subdirectories ) {
298 warn $imagesubdir if $DEBUG;
299 my @imagelist = (); # hashrefs of image info
300 my @imagenames = _getImagesFromDirectory( File::Spec->catfile( $paths->{'staff'}{'filesystem'}, $imagesubdir ) );
301 my $imagesetactive = 0;
302 foreach my $thisimage ( @imagenames ) {
303 push( @imagelist,
304 { KohaImage => "$imagesubdir/$thisimage",
305 StaffImageUrl => join( '/', $paths->{'staff'}{'url'}, $imagesubdir, $thisimage ),
306 OpacImageUrl => join( '/', $paths->{'opac'}{'url'}, $imagesubdir, $thisimage ),
307 checked => "$imagesubdir/$thisimage" eq $checked ? 1 : 0,
310 $imagesetactive = 1 if "$imagesubdir/$thisimage" eq $checked;
312 push @imagesets, { imagesetname => $imagesubdir,
313 imagesetactive => $imagesetactive,
314 images => \@imagelist };
317 return \@imagesets;
320 =head2 GetPrinters
322 $printers = &GetPrinters();
323 @queues = keys %$printers;
325 Returns information about existing printer queues.
327 C<$printers> is a reference-to-hash whose keys are the print queues
328 defined in the printers table of the Koha database. The values are
329 references-to-hash, whose keys are the fields in the printers table.
331 =cut
333 sub GetPrinters {
334 my %printers;
335 my $dbh = C4::Context->dbh;
336 my $sth = $dbh->prepare("select * from printers");
337 $sth->execute;
338 while ( my $printer = $sth->fetchrow_hashref ) {
339 $printers{ $printer->{'printqueue'} } = $printer;
341 return ( \%printers );
344 =head2 GetPrinter
346 $printer = GetPrinter( $query, $printers );
348 =cut
350 sub GetPrinter {
351 my ( $query, $printers ) = @_; # get printer for this query from printers
352 my $printer = $query->param('printer');
353 my %cookie = $query->cookie('userenv');
354 ($printer) || ( $printer = $cookie{'printer'} ) || ( $printer = '' );
355 ( $printers->{$printer} ) || ( $printer = ( keys %$printers )[0] );
356 return $printer;
359 =head2 getnbpages
361 Returns the number of pages to display in a pagination bar, given the number
362 of items and the number of items per page.
364 =cut
366 sub getnbpages {
367 my ( $nb_items, $nb_items_per_page ) = @_;
369 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
372 =head2 getallthemes
374 (@themes) = &getallthemes('opac');
375 (@themes) = &getallthemes('intranet');
377 Returns an array of all available themes.
379 =cut
381 sub getallthemes {
382 my $type = shift;
383 my $htdocs;
384 my @themes;
385 if ( $type eq 'intranet' ) {
386 $htdocs = C4::Context->config('intrahtdocs');
388 else {
389 $htdocs = C4::Context->config('opachtdocs');
391 opendir D, "$htdocs";
392 my @dirlist = readdir D;
393 foreach my $directory (@dirlist) {
394 next if $directory eq 'lib';
395 -d "$htdocs/$directory/en" and push @themes, $directory;
397 return @themes;
400 sub getFacets {
401 my $facets;
402 if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
403 $facets = [
405 idx => 'su-to',
406 label => 'Topics',
407 tags => [ qw/ 600ab 601ab 602a 604at 605a 606ax 610a / ],
408 sep => ' - ',
411 idx => 'su-geo',
412 label => 'Places',
413 tags => [ qw/ 607a / ],
414 sep => ' - ',
417 idx => 'su-ut',
418 label => 'Titles',
419 tags => [ qw/ 500a 501a 503a / ],
420 sep => ', ',
423 idx => 'au',
424 label => 'Authors',
425 tags => [ qw/ 700ab 701ab 702ab / ],
426 sep => C4::Context->preference("UNIMARCAuthorsFacetsSeparator"),
429 idx => 'se',
430 label => 'Series',
431 tags => [ qw/ 225a / ],
432 sep => ', ',
435 idx => 'location',
436 label => 'Location',
437 tags => [ qw/ 995e / ],
441 unless ( Koha::Libraries->search->count == 1 )
443 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
444 if ( $DisplayLibraryFacets eq 'both'
445 || $DisplayLibraryFacets eq 'holding' )
447 push(
448 @$facets,
450 idx => 'holdingbranch',
451 label => 'HoldingLibrary',
452 tags => [qw / 995c /],
457 if ( $DisplayLibraryFacets eq 'both'
458 || $DisplayLibraryFacets eq 'home' )
460 push(
461 @$facets,
463 idx => 'homebranch',
464 label => 'HomeLibrary',
465 tags => [qw / 995b /],
471 else {
472 $facets = [
474 idx => 'su-to',
475 label => 'Topics',
476 tags => [ qw/ 650a / ],
477 sep => '--',
480 # idx => 'su-na',
481 # label => 'People and Organizations',
482 # tags => [ qw/ 600a 610a 611a / ],
483 # sep => 'a',
484 # },
486 idx => 'su-geo',
487 label => 'Places',
488 tags => [ qw/ 651a / ],
489 sep => '--',
492 idx => 'su-ut',
493 label => 'Titles',
494 tags => [ qw/ 630a / ],
495 sep => '--',
498 idx => 'au',
499 label => 'Authors',
500 tags => [ qw/ 100a 110a 700a / ],
501 sep => ', ',
504 idx => 'se',
505 label => 'Series',
506 tags => [ qw/ 440a 490a / ],
507 sep => ', ',
510 idx => 'itype',
511 label => 'ItemTypes',
512 tags => [ qw/ 952y 942c / ],
513 sep => ', ',
516 idx => 'location',
517 label => 'Location',
518 tags => [ qw / 952c / ],
522 unless ( Koha::Libraries->search->count == 1 )
524 my $DisplayLibraryFacets = C4::Context->preference('DisplayLibraryFacets');
525 if ( $DisplayLibraryFacets eq 'both'
526 || $DisplayLibraryFacets eq 'holding' )
528 push(
529 @$facets,
531 idx => 'holdingbranch',
532 label => 'HoldingLibrary',
533 tags => [qw / 952b /],
538 if ( $DisplayLibraryFacets eq 'both'
539 || $DisplayLibraryFacets eq 'home' )
541 push(
542 @$facets,
544 idx => 'homebranch',
545 label => 'HomeLibrary',
546 tags => [qw / 952a /],
552 return $facets;
555 =head2 GetAuthorisedValues
557 $authvalues = GetAuthorisedValues([$category]);
559 This function returns all authorised values from the'authorised_value' table in a reference to array of hashrefs.
561 C<$category> returns authorised values for just one category (optional).
563 C<$opac> If set to a true value, displays OPAC descriptions rather than normal ones when they exist.
565 =cut
567 sub GetAuthorisedValues {
568 my ( $category, $opac ) = @_;
570 # Is this cached already?
571 $opac = $opac ? 1 : 0; # normalise to be safe
572 my $branch_limit =
573 C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
574 my $cache_key =
575 "AuthorisedValues-$category-$opac-$branch_limit";
576 my $cache = Koha::Caches->get_instance();
577 my $result = $cache->get_from_cache($cache_key);
578 return $result if $result;
580 my @results;
581 my $dbh = C4::Context->dbh;
582 my $query = qq{
583 SELECT DISTINCT av.*
584 FROM authorised_values av
586 $query .= qq{
587 LEFT JOIN authorised_values_branches ON ( id = av_id )
588 } if $branch_limit;
589 my @where_strings;
590 my @where_args;
591 if($category) {
592 push @where_strings, "category = ?";
593 push @where_args, $category;
595 if($branch_limit) {
596 push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
597 push @where_args, $branch_limit;
599 if(@where_strings > 0) {
600 $query .= " WHERE " . join(" AND ", @where_strings);
602 $query .= ' ORDER BY category, ' . (
603 $opac ? 'COALESCE(lib_opac, lib)'
604 : 'lib, lib_opac'
607 my $sth = $dbh->prepare($query);
609 $sth->execute( @where_args );
610 while (my $data=$sth->fetchrow_hashref) {
611 if ($opac && $data->{lib_opac}) {
612 $data->{lib} = $data->{lib_opac};
614 push @results, $data;
616 $sth->finish;
618 $cache->set_in_cache( $cache_key, \@results, { expiry => 5 } );
619 return \@results;
622 =head2 xml_escape
624 my $escaped_string = C4::Koha::xml_escape($string);
626 Convert &, <, >, ', and " in a string to XML entities
628 =cut
630 sub xml_escape {
631 my $str = shift;
632 return '' unless defined $str;
633 $str =~ s/&/&amp;/g;
634 $str =~ s/</&lt;/g;
635 $str =~ s/>/&gt;/g;
636 $str =~ s/'/&apos;/g;
637 $str =~ s/"/&quot;/g;
638 return $str;
641 =head2 display_marc_indicators
643 my $display_form = C4::Koha::display_marc_indicators($field);
645 C<$field> is a MARC::Field object
647 Generate a display form of the indicators of a variable
648 MARC field, replacing any blanks with '#'.
650 =cut
652 sub display_marc_indicators {
653 my $field = shift;
654 my $indicators = '';
655 if ($field && $field->tag() >= 10) {
656 $indicators = $field->indicator(1) . $field->indicator(2);
657 $indicators =~ s/ /#/g;
659 return $indicators;
662 sub GetNormalizedUPC {
663 my ($marcrecord,$marcflavour) = @_;
665 return unless $marcrecord;
666 if ($marcflavour eq 'UNIMARC') {
667 my @fields = $marcrecord->field('072');
668 foreach my $field (@fields) {
669 my $upc = _normalize_match_point($field->subfield('a'));
670 if ($upc) {
671 return $upc;
676 else { # assume marc21 if not unimarc
677 my @fields = $marcrecord->field('024');
678 foreach my $field (@fields) {
679 my $indicator = $field->indicator(1);
680 my $upc = _normalize_match_point($field->subfield('a'));
681 if ($upc && $indicator == 1 ) {
682 return $upc;
688 # Normalizes and returns the first valid ISBN found in the record
689 # ISBN13 are converted into ISBN10. This is required to get some book cover images.
690 sub GetNormalizedISBN {
691 my ($isbn,$marcrecord,$marcflavour) = @_;
692 if ($isbn) {
693 # Koha attempts to store multiple ISBNs in biblioitems.isbn, separated by " | "
694 # anything after " | " should be removed, along with the delimiter
695 ($isbn) = split(/\|/, $isbn );
696 return _isbn_cleanup($isbn);
699 return unless $marcrecord;
701 if ($marcflavour eq 'UNIMARC') {
702 my @fields = $marcrecord->field('010');
703 foreach my $field (@fields) {
704 my $isbn = $field->subfield('a');
705 if ($isbn) {
706 return _isbn_cleanup($isbn);
710 else { # assume marc21 if not unimarc
711 my @fields = $marcrecord->field('020');
712 foreach my $field (@fields) {
713 $isbn = $field->subfield('a');
714 if ($isbn) {
715 return _isbn_cleanup($isbn);
721 sub GetNormalizedEAN {
722 my ($marcrecord,$marcflavour) = @_;
724 return unless $marcrecord;
726 if ($marcflavour eq 'UNIMARC') {
727 my @fields = $marcrecord->field('073');
728 foreach my $field (@fields) {
729 my $ean = _normalize_match_point($field->subfield('a'));
730 if ( $ean ) {
731 return $ean;
735 else { # assume marc21 if not unimarc
736 my @fields = $marcrecord->field('024');
737 foreach my $field (@fields) {
738 my $indicator = $field->indicator(1);
739 my $ean = _normalize_match_point($field->subfield('a'));
740 if ( $ean && $indicator == 3 ) {
741 return $ean;
747 sub GetNormalizedOCLCNumber {
748 my ($marcrecord,$marcflavour) = @_;
749 return unless $marcrecord;
751 if ($marcflavour ne 'UNIMARC' ) {
752 my @fields = $marcrecord->field('035');
753 foreach my $field (@fields) {
754 my $oclc = $field->subfield('a');
755 if ($oclc =~ /OCoLC/) {
756 $oclc =~ s/\(OCoLC\)//;
757 return $oclc;
760 } else {
761 # TODO for UNIMARC
763 return
766 =head2 GetDailyQuote($opts)
768 Takes a hashref of options
770 Currently supported options are:
772 'id' An exact quote id
773 'random' Select a random quote
774 noop When no option is passed in, this sub will return the quote timestamped for the current day
776 The function returns an anonymous hash following this format:
779 'source' => 'source-of-quote',
780 'timestamp' => 'timestamp-value',
781 'text' => 'text-of-quote',
782 'id' => 'quote-id'
785 =cut
787 # This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
788 # at least for default option
790 sub GetDailyQuote {
791 my %opts = @_;
792 my $dbh = C4::Context->dbh;
793 my $query = '';
794 my $sth = undef;
795 my $quote = undef;
796 if ($opts{'id'}) {
797 $query = 'SELECT * FROM quotes WHERE id = ?';
798 $sth = $dbh->prepare($query);
799 $sth->execute($opts{'id'});
800 $quote = $sth->fetchrow_hashref();
802 elsif ($opts{'random'}) {
803 # Fall through... we also return a random quote as a catch-all if all else fails
805 else {
806 $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp DESC LIMIT 0,1';
807 $sth = $dbh->prepare($query);
808 $sth->execute();
809 $quote = $sth->fetchrow_hashref();
811 unless ($quote) { # if there are not matches, choose a random quote
812 # get a list of all available quote ids
813 $sth = C4::Context->dbh->prepare('SELECT count(*) FROM quotes;');
814 $sth->execute;
815 my $range = ($sth->fetchrow_array)[0];
816 # chose a random id within that range if there is more than one quote
817 my $offset = int(rand($range));
818 # grab it
819 $query = 'SELECT * FROM quotes ORDER BY id LIMIT 1 OFFSET ?';
820 $sth = C4::Context->dbh->prepare($query);
821 # see http://www.perlmonks.org/?node_id=837422 for why
822 # we're being verbose and using bind_param
823 $sth->bind_param(1, $offset, SQL_INTEGER);
824 $sth->execute();
825 $quote = $sth->fetchrow_hashref();
826 # update the timestamp for that quote
827 $query = 'UPDATE quotes SET timestamp = ? WHERE id = ?';
828 $sth = C4::Context->dbh->prepare($query);
829 $sth->execute(
830 DateTime::Format::MySQL->format_datetime( dt_from_string() ),
831 $quote->{'id'}
834 return $quote;
837 sub _normalize_match_point {
838 my $match_point = shift;
839 (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
840 $normalized_match_point =~ s/-//g;
842 return $normalized_match_point;
845 sub _isbn_cleanup {
846 my ($isbn) = @_;
847 return NormalizeISBN(
849 isbn => $isbn,
850 format => 'ISBN-10',
851 strip_hyphens => 1,
853 ) if $isbn;
856 =head2 NormalizedISBN
858 my $isbns = NormalizedISBN({
859 isbn => $isbn,
860 strip_hyphens => [0,1],
861 format => ['ISBN-10', 'ISBN-13']
864 Returns an isbn validated by Business::ISBN.
865 Optionally strips hyphens and/or forces the isbn
866 to be of the specified format.
868 If the string cannot be validated as an isbn,
869 it returns nothing.
871 =cut
873 sub NormalizeISBN {
874 my ($params) = @_;
876 my $string = $params->{isbn};
877 my $strip_hyphens = $params->{strip_hyphens};
878 my $format = $params->{format};
880 return unless $string;
882 my $isbn = Business::ISBN->new($string);
884 if ( $isbn && $isbn->is_valid() ) {
886 if ( $format eq 'ISBN-10' ) {
887 $isbn = $isbn->as_isbn10();
889 elsif ( $format eq 'ISBN-13' ) {
890 $isbn = $isbn->as_isbn13();
892 return unless $isbn;
894 if ($strip_hyphens) {
895 $string = $isbn->as_string( [] );
896 } else {
897 $string = $isbn->as_string();
900 return $string;
904 =head2 GetVariationsOfISBN
906 my @isbns = GetVariationsOfISBN( $isbn );
908 Returns a list of variations of the given isbn in
909 both ISBN-10 and ISBN-13 formats, with and without
910 hyphens.
912 In a scalar context, the isbns are returned as a
913 string delimited by ' | '.
915 =cut
917 sub GetVariationsOfISBN {
918 my ($isbn) = @_;
920 return unless $isbn;
922 my @isbns;
924 push( @isbns, NormalizeISBN({ isbn => $isbn }) );
925 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10' }) );
926 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13' }) );
927 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-10', strip_hyphens => 1 }) );
928 push( @isbns, NormalizeISBN({ isbn => $isbn, format => 'ISBN-13', strip_hyphens => 1 }) );
930 # Strip out any "empty" strings from the array
931 @isbns = grep { defined($_) && $_ =~ /\S/ } @isbns;
933 return wantarray ? @isbns : join( " | ", @isbns );
936 =head2 GetVariationsOfISBNs
938 my @isbns = GetVariationsOfISBNs( @isbns );
940 Returns a list of variations of the given isbns in
941 both ISBN-10 and ISBN-13 formats, with and without
942 hyphens.
944 In a scalar context, the isbns are returned as a
945 string delimited by ' | '.
947 =cut
949 sub GetVariationsOfISBNs {
950 my (@isbns) = @_;
952 @isbns = map { GetVariationsOfISBN( $_ ) } @isbns;
954 return wantarray ? @isbns : join( " | ", @isbns );
957 =head2 NormalizedISSN
959 my $issns = NormalizedISSN({
960 issn => $issn,
961 strip_hyphen => [0,1]
964 Returns an issn validated by Business::ISSN.
965 Optionally strips hyphen.
967 If the string cannot be validated as an issn,
968 it returns nothing.
970 =cut
972 sub NormalizeISSN {
973 my ($params) = @_;
975 my $string = $params->{issn};
976 my $strip_hyphen = $params->{strip_hyphen};
978 my $issn = Business::ISSN->new($string);
980 if ( $issn && $issn->is_valid ){
982 if ($strip_hyphen) {
983 $string = $issn->_issn;
985 else {
986 $string = $issn->as_string;
988 return $string;
993 =head2 GetVariationsOfISSN
995 my @issns = GetVariationsOfISSN( $issn );
997 Returns a list of variations of the given issn in
998 with and without a hyphen.
1000 In a scalar context, the issns are returned as a
1001 string delimited by ' | '.
1003 =cut
1005 sub GetVariationsOfISSN {
1006 my ( $issn ) = @_;
1008 return unless $issn;
1010 my @issns;
1011 my $str = NormalizeISSN({ issn => $issn });
1012 if( $str ) {
1013 push @issns, $str;
1014 push @issns, NormalizeISSN({ issn => $issn, strip_hyphen => 1 });
1015 } else {
1016 push @issns, $issn;
1019 # Strip out any "empty" strings from the array
1020 @issns = grep { defined($_) && $_ =~ /\S/ } @issns;
1022 return wantarray ? @issns : join( " | ", @issns );
1025 =head2 GetVariationsOfISSNs
1027 my @issns = GetVariationsOfISSNs( @issns );
1029 Returns a list of variations of the given issns in
1030 with and without a hyphen.
1032 In a scalar context, the issns are returned as a
1033 string delimited by ' | '.
1035 =cut
1037 sub GetVariationsOfISSNs {
1038 my (@issns) = @_;
1040 @issns = map { GetVariationsOfISSN( $_ ) } @issns;
1042 return wantarray ? @issns : join( " | ", @issns );
1046 =head2 IsKohaFieldLinked
1048 my $is_linked = IsKohaFieldLinked({
1049 kohafield => $kohafield,
1050 frameworkcode => $frameworkcode,
1053 Return 1 if the field is linked
1055 =cut
1057 sub IsKohaFieldLinked {
1058 my ( $params ) = @_;
1059 my $kohafield = $params->{kohafield};
1060 my $frameworkcode = $params->{frameworkcode} || '';
1061 my $dbh = C4::Context->dbh;
1062 my $is_linked = $dbh->selectcol_arrayref( q|
1063 SELECT COUNT(*)
1064 FROM marc_subfield_structure
1065 WHERE frameworkcode = ?
1066 AND kohafield = ?
1067 |,{}, $frameworkcode, $kohafield );
1068 return $is_linked->[0];
1073 __END__
1075 =head1 AUTHOR
1077 Koha Team
1079 =cut