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
45 &GetItemTypesCategorized
51 &getitemtypeimagelocation
56 &GetNormalizedOCLCNumber
69 @EXPORT_OK = qw( GetDailyQuote );
74 C4::Koha - Perl Module containing convenience functions for Koha scripts
82 Koha.pm provides many functions for Koha scripts.
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)
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.
103 SELECT itemtype
, description
, imageurl
, hideinopac
, 0 as
'iscat' FROM itemtypes WHERE ISNULL
(searchcategory
) or length(searchcategory
) = 0
105 SELECT DISTINCT searchcategory AS
`itemtype`,
106 authorised_values
.lib_opac AS description
,
107 authorised_values
.imageurl AS imageurl
,
108 hideinopac
, 1 as
'iscat'
110 LEFT JOIN authorised_values ON searchcategory
= authorised_value
111 WHERE searchcategory
> '' and hideinopac
=1
113 SELECT DISTINCT searchcategory AS
`itemtype`,
114 authorised_values
.lib_opac AS description
,
115 authorised_values
.imageurl AS imageurl
,
116 hideinopac
, 1 as
'iscat'
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.
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
|
142 itemtypes
.description
,
143 itemtypes
.rentalcharge
,
144 itemtypes
.notforloan
,
147 itemtypes
.checkinmsg
,
148 itemtypes
.checkinmsgtype
,
149 itemtypes
.sip_media_type
,
150 COALESCE
( localization
.translation
, itemtypes
.description
) AS translated_description
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
} );
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.
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';
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';
187 return '/opac-tmpl' . '/' . C4
::Context
->preference('opacthemes') . '/itemtypeimg';
191 sub getitemtypeimagelocation
{
192 my ( $src, $image ) = @_;
194 return '' if ( !$image );
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.
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 );
227 @images = sort(@images);
230 warn "unable to opendir $directoryname: $!";
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.
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 );
259 warn "unable to opendir $directoryname: $!";
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.
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 ) {
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 };
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.
335 my $dbh = C4
::Context
->dbh;
336 my $sth = $dbh->prepare("select * from printers");
338 while ( my $printer = $sth->fetchrow_hashref ) {
339 $printers{ $printer->{'printqueue'} } = $printer;
341 return ( \
%printers );
346 $printer = GetPrinter( $query, $printers );
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] );
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.
367 my ( $nb_items, $nb_items_per_page ) = @_;
369 return int( ( $nb_items - 1 ) / $nb_items_per_page ) + 1;
374 (@themes) = &getallthemes('opac');
375 (@themes) = &getallthemes('intranet');
377 Returns an array of all available themes.
385 if ( $type eq 'intranet' ) {
386 $htdocs = C4
::Context
->config('intrahtdocs');
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;
402 if ( C4
::Context
->preference("marcflavour") eq "UNIMARC" ) {
407 tags
=> [ qw
/ 600ab 601ab 602a 604at 605a 606ax 610a / ],
413 tags
=> [ qw
/ 607a / ],
419 tags
=> [ qw
/ 500a 501a 503a / ],
425 tags
=> [ qw
/ 700ab 701ab 702ab / ],
426 sep
=> C4
::Context
->preference("UNIMARCAuthorsFacetsSeparator"),
431 tags
=> [ qw
/ 225a / ],
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' )
450 idx
=> 'holdingbranch',
451 label
=> 'HoldingLibrary',
452 tags
=> [qw
/ 995c /],
457 if ( $DisplayLibraryFacets eq 'both'
458 || $DisplayLibraryFacets eq 'home' )
464 label
=> 'HomeLibrary',
465 tags
=> [qw
/ 995b /],
476 tags
=> [ qw
/ 650a / ],
481 # label => 'People and Organizations',
482 # tags => [ qw/ 600a 610a 611a / ],
488 tags
=> [ qw
/ 651a / ],
494 tags
=> [ qw
/ 630a / ],
500 tags
=> [ qw
/ 100a 110a 700a / ],
506 tags
=> [ qw
/ 440a 490a / ],
511 label
=> 'ItemTypes',
512 tags
=> [ qw
/ 952y 942c / ],
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' )
531 idx
=> 'holdingbranch',
532 label
=> 'HoldingLibrary',
533 tags
=> [qw
/ 952b /],
538 if ( $DisplayLibraryFacets eq 'both'
539 || $DisplayLibraryFacets eq 'home' )
545 label
=> 'HomeLibrary',
546 tags
=> [qw
/ 952a /],
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.
567 sub GetAuthorisedValues
{
568 my ( $category, $opac ) = @_;
570 # Is this cached already?
571 $opac = $opac ?
1 : 0; # normalise to be safe
573 C4
::Context
->userenv ? C4
::Context
->userenv->{"branch"} : "";
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;
581 my $dbh = C4
::Context
->dbh;
584 FROM authorised_values av
587 LEFT JOIN authorised_values_branches ON
( id
= av_id
)
592 push @where_strings, "category = ?";
593 push @where_args, $category;
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)'
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;
618 $cache->set_in_cache( $cache_key, \
@results, { expiry
=> 5 } );
624 my $escaped_string = C4::Koha::xml_escape($string);
626 Convert &, <, >, ', and " in a string to XML entities
632 return '' unless defined $str;
636 $str =~ s/'/'/g;
637 $str =~ s/"/"/g;
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 '#'.
652 sub display_marc_indicators
{
655 if ($field && $field->tag() >= 10) {
656 $indicators = $field->indicator(1) . $field->indicator(2);
657 $indicators =~ s/ /#/g;
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'));
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 ) {
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) = @_;
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');
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');
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'));
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 ) {
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\)//;
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',
787 # This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
788 # at least for default option
792 my $dbh = C4
::Context
->dbh;
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
806 $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp DESC LIMIT 0,1';
807 $sth = $dbh->prepare($query);
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;');
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));
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
);
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);
830 DateTime
::Format
::MySQL
->format_datetime( dt_from_string
() ),
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;
847 return NormalizeISBN
(
856 =head2 NormalizedISBN
858 my $isbns = NormalizedISBN({
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,
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();
894 if ($strip_hyphens) {
895 $string = $isbn->as_string( [] );
897 $string = $isbn->as_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
912 In a scalar context, the isbns are returned as a
913 string delimited by ' | '.
917 sub GetVariationsOfISBN
{
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
944 In a scalar context, the isbns are returned as a
945 string delimited by ' | '.
949 sub GetVariationsOfISBNs
{
952 @isbns = map { GetVariationsOfISBN
( $_ ) } @isbns;
954 return wantarray ?
@isbns : join( " | ", @isbns );
957 =head2 NormalizedISSN
959 my $issns = NormalizedISSN({
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,
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 ){
983 $string = $issn->_issn;
986 $string = $issn->as_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 ' | '.
1005 sub GetVariationsOfISSN
{
1008 return unless $issn;
1011 my $str = NormalizeISSN
({ issn
=> $issn });
1014 push @issns, NormalizeISSN
({ issn
=> $issn, strip_hyphen
=> 1 });
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 ' | '.
1037 sub GetVariationsOfISSNs
{
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
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
|
1064 FROM marc_subfield_structure
1065 WHERE frameworkcode
= ?
1067 |,{}, $frameworkcode, $kohafield );
1068 return $is_linked->[0];