Bug 8435: DBRev 3.13.00.038
[koha.git] / C4 / Koha.pm
index 43bfdf5..937ac5f 100644 (file)
@@ -22,13 +22,18 @@ package C4::Koha;
 
 use strict;
 #use warnings; FIXME - Bug 2505
+
 use C4::Context;
+use C4::Branch qw(GetBranchesCount);
+use Koha::DateUtils qw(dt_from_string);
 use Memoize;
+use DateTime::Format::MySQL;
+use autouse 'Data::Dumper' => qw(Dumper);
 
-use vars qw($VERSION @ISA @EXPORT $DEBUG);
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $DEBUG);
 
 BEGIN {
-       $VERSION = 3.01;
+    $VERSION = 3.07.00.049;
        require Exporter;
        @ISA    = qw(Exporter);
        @EXPORT = qw(
@@ -36,7 +41,6 @@ BEGIN {
                &subfield_is_koha_internal_p
                &GetPrinters &GetPrinter
                &GetItemTypes &getitemtypeinfo
-               &GetCcodes
                &GetSupportName &GetSupportList
                &get_itemtypeinfos_of
                &getframeworks &getframeworkinfo
@@ -52,12 +56,14 @@ BEGIN {
                &getitemtypeimagelocation
                &GetAuthorisedValues
                &GetAuthorisedValueCategories
+                &IsAuthorisedValueCategory
                &GetKohaAuthorisedValues
                &GetKohaAuthorisedValuesFromField
     &GetKohaAuthorisedValueLib
     &GetAuthorisedValueByCode
     &GetKohaImageurlFromAuthorisedValues
                &GetAuthValCode
+        &AddAuthorisedValue
                &GetNormalizedUPC
                &GetNormalizedISBN
                &GetNormalizedEAN
@@ -67,6 +73,7 @@ BEGIN {
                $DEBUG
        );
        $DEBUG = 0;
+@EXPORT_OK = qw( GetDailyQuote );
 }
 
 # expensive functions
@@ -106,7 +113,7 @@ sub slashifyDate {
 }
 
 # FIXME.. this should be moved to a MARC-specific module
-sub subfield_is_koha_internal_p ($) {
+sub subfield_is_koha_internal_p {
     my ($subfield) = @_;
 
     # We could match on 'lib' and 'tab' (and 'mandatory', & more to come!)
@@ -166,16 +173,16 @@ build a HTML select with the following code :
 
 =head3 in TEMPLATE
 
-    <form action='<!-- TMPL_VAR name="script_name" -->' method=post>
-        <select name="itemtype">
-            <option value="">Default</option>
-        <!-- TMPL_LOOP name="itemtypeloop" -->
-            <option value="<!-- TMPL_VAR name="itemtype" -->" <!-- TMPL_IF name="selected" -->selected<!-- /TMPL_IF -->> <!--TMPL_IF Name="imageurl"--><img alt="<!-- TMPL_VAR name="description" -->" src="<!--TMPL_VAR Name="imageurl"-->><!--TMPL_ELSE-->"<!-- TMPL_VAR name="description" --><!--/TMPL_IF--></option>
-        <!-- /TMPL_LOOP -->
-        </select>
-        <input type=text name=searchfield value="<!-- TMPL_VAR name="searchfield" -->">
-        <input type="submit" value="OK" class="button">
-    </form>
+    <select name="itemtype" id="itemtype">
+        <option value=""></option>
+        [% FOREACH itemtypeloo IN itemtypeloop %]
+             [% IF ( itemtypeloo.selected ) %]
+                <option value="[% itemtypeloo.itemtype %]" selected="selected">[% itemtypeloo.description %]</option>
+            [% ELSE %]
+                <option value="[% itemtypeloo.itemtype %]">[% itemtypeloo.description %]</option>
+            [% END %]
+       [% END %]
+    </select>
 
 =cut
 
@@ -198,10 +205,15 @@ sub GetSupportList{
 }
 =head2 GetItemTypes
 
-  $itemtypes = &GetItemTypes();
+  $itemtypes = &GetItemTypes( style => $style );
 
 Returns information about existing itemtypes.
 
+Params:
+    style: either 'array' or 'hash', defaults to 'hash'.
+           'array' returns an arrayref,
+           'hash' return a hashref with the itemtype value as the key
+
 build a HTML select with the following code :
 
 =head3 in PERL SCRIPT
@@ -234,6 +246,8 @@ build a HTML select with the following code :
 =cut
 
 sub GetItemTypes {
+    my ( %params ) = @_;
+    my $style = defined( $params{'style'} ) ? $params{'style'} : 'hash';
 
     # returns a reference to a hash of references to itemtypes...
     my %itemtypes;
@@ -244,10 +258,15 @@ sub GetItemTypes {
     |;
     my $sth = $dbh->prepare($query);
     $sth->execute;
-    while ( my $IT = $sth->fetchrow_hashref ) {
-        $itemtypes{ $IT->{'itemtype'} } = $IT;
+
+    if ( $style eq 'hash' ) {
+        while ( my $IT = $sth->fetchrow_hashref ) {
+            $itemtypes{ $IT->{'itemtype'} } = $IT;
+        }
+        return ( \%itemtypes );
+    } else {
+        return $sth->fetchall_arrayref({});
     }
-    return ( \%itemtypes );
 }
 
 sub get_itemtypeinfos_of {
@@ -266,27 +285,6 @@ END_SQL
     return get_infos_of( $query, 'itemtype', undef, \@itemtypes );
 }
 
-# this is temporary until we separate collection codes and item types
-sub GetCcodes {
-    my $count = 0;
-    my @results;
-    my $dbh = C4::Context->dbh;
-    my $sth =
-      $dbh->prepare(
-        "SELECT * FROM authorised_values ORDER BY authorised_value");
-    $sth->execute;
-    while ( my $data = $sth->fetchrow_hashref ) {
-        if ( $data->{category} eq "CCODE" ) {
-            $count++;
-            $results[$count] = $data;
-
-            #warn "data: $data";
-        }
-    }
-    $sth->finish;
-    return ( $count, @results );
-}
-
 =head2 getauthtypes
 
   $authtypes = &getauthtypes();
@@ -419,20 +417,22 @@ sub getframeworkinfo {
 
 =head2 getitemtypeinfo
 
-  $itemtype = &getitemtype($itemtype);
+  $itemtype = &getitemtypeinfo($itemtype, [$interface]);
 
-Returns information about an itemtype.
+Returns information about an itemtype. The optional $interface argument
+sets which interface ('opac' or 'intranet') to return the imageurl for.
+Defaults to intranet.
 
 =cut
 
 sub getitemtypeinfo {
-    my ($itemtype) = @_;
+    my ($itemtype, $interface) = @_;
     my $dbh        = C4::Context->dbh;
     my $sth        = $dbh->prepare("select * from itemtypes where itemtype=?");
     $sth->execute($itemtype);
     my $res = $sth->fetchrow_hashref;
 
-    $res->{imageurl} = getitemtypeimagelocation( 'intranet', $res->{imageurl} );
+    $res->{imageurl} = getitemtypeimagelocation( ( ( defined $interface && $interface eq 'opac' ) ? 'opac' : 'intranet' ), $res->{imageurl} );
 
     return $res;
 }
@@ -465,7 +465,7 @@ sub getitemtypeimagesrc {
        }
 }
 
-sub getitemtypeimagelocation($$) {
+sub getitemtypeimagelocation {
        my ( $src, $image ) = @_;
 
        return '' if ( !$image );
@@ -624,7 +624,7 @@ sub GetPrinters {
 
 =cut
 
-sub GetPrinter ($$) {
+sub GetPrinter {
     my ( $query, $printers ) = @_;    # get printer for this query from printers
     my $printer = $query->param('printer');
     my %cookie = $query->cookie('userenv');
@@ -668,6 +668,7 @@ sub getallthemes {
     opendir D, "$htdocs";
     my @dirlist = readdir D;
     foreach my $directory (@dirlist) {
+        next if $directory eq 'lib';
         -d "$htdocs/$directory/en" and push @themes, $directory;
     }
     return @themes;
@@ -678,98 +679,112 @@ sub getFacets {
     if ( C4::Context->preference("marcflavour") eq "UNIMARC" ) {
         $facets = [
             {
-                link_value  => 'su-to',
-                label_value => 'Topics',
-                tags        =>
-                  [ '600', '601', '602', '603', '604', '605', '606', '610' ],
-                subfield => 'a',
+                idx   => 'su-to',
+                label => 'Topics',
+                tags  => [ qw/ 600ab 601ab 602a 604at 605a 606ax 610a / ],
+                sep   => ' - ',
             },
             {
-                link_value  => 'su-geo',
-                label_value => 'Places',
-                tags        => ['651'],
-                subfield    => 'a',
+                idx   => 'su-geo',
+                label => 'Places',
+                tags  => [ qw/ 607a / ],
+                sep   => ' - ',
             },
             {
-                link_value  => 'su-ut',
-                label_value => 'Titles',
-                tags        => [ '500', '501', '502', '503', '504', ],
-                subfield    => 'a',
+                idx   => 'su-ut',
+                label => 'Titles',
+                tags  => [ qw/ 500a 501a 503a / ],
+                sep   => ', ',
             },
             {
-                link_value  => 'au',
-                label_value => 'Authors',
-                tags        => [ '700', '701', '702', ],
-                subfield    => 'a',
+                idx   => 'au',
+                label => 'Authors',
+                tags  => [ qw/ 700ab 701ab 702ab / ],
+                sep   => C4::Context->preference("UNIMARCAuthorsFacetsSeparator"),
             },
             {
-                link_value  => 'se',
-                label_value => 'Series',
-                tags        => ['225'],
-                subfield    => 'a',
+                idx   => 'se',
+                label => 'Series',
+                tags  => [ qw/ 225a / ],
+                sep   => ', ',
             },
+            {
+                idx  => 'location',
+                label => 'Location',
+                tags        => [ qw/ 995c / ],
+            }
             ];
 
             my $library_facet;
-
-            $library_facet = {
-                link_value  => 'branch',
-                label_value => 'Libraries',
-                tags        => [ '995', ],
-                subfield    => 'b',
-                expanded    => '1',
-            };
-            push @$facets, $library_facet unless C4::Context->preference("singleBranchMode");
+            unless ( C4::Context->preference("singleBranchMode") || GetBranchesCount() == 1 ) {
+                $library_facet = {
+                    idx  => 'branch',
+                    label => 'Libraries',
+                    tags        => [ qw/ 995b / ],
+                };
+            }
+            push( @$facets, $library_facet );
     }
     else {
         $facets = [
             {
-                link_value  => 'su-to',
-                label_value => 'Topics',
-                tags        => ['650'],
-                subfield    => 'a',
+                idx   => 'su-to',
+                label => 'Topics',
+                tags  => [ qw/ 650a / ],
+                sep   => '--',
             },
-
             #        {
-            #        link_value => 'su-na',
-            #        label_value => 'People and Organizations',
-            #        tags => ['600', '610', '611'],
-            #        subfield => 'a',
+            #        idx   => 'su-na',
+            #        label => 'People and Organizations',
+            #        tags  => [ qw/ 600a 610a 611a / ],
+            #        sep   => 'a',
             #        },
             {
-                link_value  => 'su-geo',
-                label_value => 'Places',
-                tags        => ['651'],
-                subfield    => 'a',
+                idx   => 'su-geo',
+                label => 'Places',
+                tags  => [ qw/ 651a / ],
+                sep   => '--',
+            },
+            {
+                idx   => 'su-ut',
+                label => 'Titles',
+                tags  => [ qw/ 630a / ],
+                sep   => '--',
+            },
+            {
+                idx   => 'au',
+                label => 'Authors',
+                tags  => [ qw/ 100a 110a 700a / ],
+                sep   => ', ',
             },
             {
-                link_value  => 'su-ut',
-                label_value => 'Titles',
-                tags        => ['630'],
-                subfield    => 'a',
+                idx   => 'se',
+                label => 'Series',
+                tags  => [ qw/ 440a 490a / ],
+                sep   => ', ',
             },
             {
-                link_value  => 'au',
-                label_value => 'Authors',
-                tags        => [ '100', '110', '700', ],
-                subfield    => 'a',
+                idx   => 'itype',
+                label => 'ItemTypes',
+                tags  => [ qw/ 952y 942c / ],
+                sep   => ', ',
             },
             {
-                link_value  => 'se',
-                label_value => 'Series',
-                tags        => [ '440', '490', ],
-                subfield    => 'a',
+                idx => 'location',
+                label => 'Location',
+                tags => [ qw / 952c / ],
             },
             ];
+
             my $library_facet;
-            $library_facet = {
-                link_value  => 'branch',
-                label_value => 'Libraries',
-                tags        => [ '952', ],
-                subfield    => 'b',
-                expanded    => '1',
-            };
-            push @$facets, $library_facet unless C4::Context->preference("singleBranchMode");
+            unless ( C4::Context->preference("singleBranchMode") || GetBranchesCount() == 1 ) {
+                $library_facet = {
+                    idx  => 'branch',
+                    label => 'Libraries',
+                    tags        => [ qw / 952b / ],
+                };
+            }
+            push( @$facets, $library_facet );
     }
     return $facets;
 }
@@ -886,13 +901,13 @@ like:
 
     {
       'checked'    => 'checked',
-      'encoding'   => 'MARC-8'
+      'encoding'   => 'utf8',
       'icon'       => undef,
       'id'         => 'LIBRARY OF CONGRESS',
       'label'      => '',
       'name'       => 'server',
       'opensearch' => '',
-      'value'      => 'z3950.loc.gov:7090/',
+      'value'      => 'lx2.loc.gov:210/',
       'zed'        => 1,
     },
 
@@ -1013,25 +1028,54 @@ C<$opac> If set to a true value, displays OPAC descriptions rather than normal o
 =cut
 
 sub GetAuthorisedValues {
-    my ($category,$selected,$opac) = @_;
-       my @results;
+    my ( $category, $selected, $opac ) = @_;
+    my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : "";
+    my @results;
     my $dbh      = C4::Context->dbh;
-    my $query    = "SELECT * FROM authorised_values";
-    $query .= " WHERE category = '" . $category . "'" if $category;
-    $query .= " ORDER BY category, lib, lib_opac";
+    my $query = qq{
+        SELECT *
+        FROM authorised_values
+    };
+    $query .= qq{
+          LEFT JOIN authorised_values_branches ON ( id = av_id )
+    } if $branch_limit;
+    my @where_strings;
+    my @where_args;
+    if($category) {
+        push @where_strings, "category = ?";
+        push @where_args, $category;
+    }
+    if($branch_limit) {
+        push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
+        push @where_args, $branch_limit;
+    }
+    if(@where_strings > 0) {
+        $query .= " WHERE " . join(" AND ", @where_strings);
+    }
+    $query .= " GROUP BY lib";
+    $query .= ' ORDER BY category, ' . (
+                $opac ? 'COALESCE(lib_opac, lib)'
+                      : 'lib, lib_opac'
+              );
+
     my $sth = $dbh->prepare($query);
-    $sth->execute;
-       while (my $data=$sth->fetchrow_hashref) {
-           if ($selected && $selected eq $data->{'authorised_value'} ) {
-                   $data->{'selected'} = 1;
-           }
-           if ($opac && $data->{'lib_opac'}) {
-               $data->{'lib'} = $data->{'lib_opac'};
-           }
-           push @results, $data;
-       }
-    #my $data = $sth->fetchall_arrayref({});
-    return \@results; #$data;
+
+    $sth->execute( @where_args );
+    while (my $data=$sth->fetchrow_hashref) {
+        if ( defined $selected and $selected eq $data->{authorised_value} ) {
+            $data->{selected} = 1;
+        }
+        else {
+            $data->{selected} = 0;
+        }
+
+        if ($opac && $data->{lib_opac}) {
+            $data->{lib} = $data->{lib_opac};
+        }
+        push @results, $data;
+    }
+    $sth->finish;
+    return \@results;
 }
 
 =head2 GetAuthorisedValueCategories
@@ -1054,9 +1098,31 @@ sub GetAuthorisedValueCategories {
     return \@results;
 }
 
+=head2 IsAuthorisedValueCategory
+
+    $is_auth_val_category = IsAuthorisedValueCategory($category);
+
+Returns whether a given category name is a valid one
+
+=cut
+
+sub IsAuthorisedValueCategory {
+    my $category = shift;
+    my $query = '
+        SELECT category
+        FROM authorised_values
+        WHERE BINARY category=?
+        LIMIT 1
+    ';
+    my $sth = C4::Context->dbh->prepare($query);
+    $sth->execute($category);
+    $sth->fetchrow ? return 1
+                   : return 0;
+}
+
 =head2 GetAuthorisedValueByCode
 
-$authhorised_value = GetAuthorisedValueByCode( $category, $authvalcode );
+$authorised_value = GetAuthorisedValueByCode( $category, $authvalcode, $opac );
 
 Return the lib attribute from authorised_values from the row identified
 by the passed category and code
@@ -1064,13 +1130,14 @@ by the passed category and code
 =cut
 
 sub GetAuthorisedValueByCode {
-    my ( $category, $authvalcode ) = @_;
+    my ( $category, $authvalcode, $opac ) = @_;
 
+    my $field = $opac ? 'lib_opac' : 'lib';
     my $dbh = C4::Context->dbh;
-    my $sth = $dbh->prepare("SELECT lib FROM authorised_values WHERE category=? AND authorised_value =?");
+    my $sth = $dbh->prepare("SELECT $field FROM authorised_values WHERE category=? AND authorised_value =?");
     $sth->execute( $category, $authvalcode );
     while ( my $data = $sth->fetchrow_hashref ) {
-        return $data->{'lib'};
+        return $data->{ $field };
     }
 }
 
@@ -1100,7 +1167,7 @@ sub GetKohaAuthorisedValues {
        }
        return \%values;
   } else {
-       return undef;
+       return;
   }
 }
 
@@ -1131,7 +1198,7 @@ sub GetKohaAuthorisedValuesFromField {
        }
        return \%values;
   } else {
-       return undef;
+       return;
   }
 }
 
@@ -1175,6 +1242,26 @@ sub GetKohaAuthorisedValueLib {
   return $value;
 }
 
+=head2 AddAuthorisedValue
+
+    AddAuthorisedValue($category, $authorised_value, $lib, $lib_opac, $imageurl);
+
+Create a new authorised value.
+
+=cut
+
+sub AddAuthorisedValue {
+    my ($category, $authorised_value, $lib, $lib_opac, $imageurl) = @_;
+
+    my $dbh = C4::Context->dbh;
+    my $query = qq{
+        INSERT INTO authorised_values (category, authorised_value, lib, lib_opac, imageurl)
+        VALUES (?,?,?,?,?)
+    };
+    my $sth = $dbh->prepare($query);
+    $sth->execute($category, $authorised_value, $lib, $lib_opac, $imageurl);
+}
+
 =head2 display_marc_indicators
 
   my $display_form = C4::Koha::display_marc_indicators($field);
@@ -1223,7 +1310,7 @@ sub GetNormalizedUPC {
 }
 
 # Normalizes and returns the first valid ISBN found in the record
-# ISBN13 are converted into ISBN10. This is required to get Amazon cover book.
+# ISBN13 are converted into ISBN10. This is required to get some book cover images.
 sub GetNormalizedISBN {
     my ($isbn,$record,$marcflavour) = @_;
     my @fields;
@@ -1233,7 +1320,7 @@ sub GetNormalizedISBN {
         $isbn =~ s/(.*)( \| )(.*)/$1/;
         return _isbn_cleanup($isbn);
     }
-    return undef unless $record;
+    return unless $record;
 
     if ($marcflavour eq 'UNIMARC') {
         @fields = $record->field('010');
@@ -1242,7 +1329,7 @@ sub GetNormalizedISBN {
             if ($isbn) {
                 return _isbn_cleanup($isbn);
             } else {
-                return undef;
+                return;
             }
         }
     }
@@ -1253,7 +1340,7 @@ sub GetNormalizedISBN {
             if ($isbn) {
                 return _isbn_cleanup($isbn);
             } else {
-                return undef;
+                return;
             }
         }
     }
@@ -1298,12 +1385,87 @@ sub GetNormalizedOCLCNumber {
                 $oclc =~ s/\(OCoLC\)//;
                 return $oclc;
             } else {
-                return undef;
+                return;
             }
         }
     }
 }
 
+=head2 GetDailyQuote($opts)
+
+Takes a hashref of options
+
+Currently supported options are:
+
+'id'        An exact quote id
+'random'    Select a random quote
+noop        When no option is passed in, this sub will return the quote timestamped for the current day
+
+The function returns an anonymous hash following this format:
+
+        {
+          'source' => 'source-of-quote',
+          'timestamp' => 'timestamp-value',
+          'text' => 'text-of-quote',
+          'id' => 'quote-id'
+        };
+
+=cut
+
+# This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
+# at least for default option
+
+sub GetDailyQuote {
+    my %opts = @_;
+    my $dbh = C4::Context->dbh;
+    my $query = '';
+    my $sth = undef;
+    my $quote = undef;
+    if ($opts{'id'}) {
+        $query = 'SELECT * FROM quotes WHERE id = ?';
+        $sth = $dbh->prepare($query);
+        $sth->execute($opts{'id'});
+        $quote = $sth->fetchrow_hashref();
+    }
+    elsif ($opts{'random'}) {
+        # Fall through... we also return a random quote as a catch-all if all else fails
+    }
+    else {
+        $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp DESC LIMIT 0,1';
+        $sth = $dbh->prepare($query);
+        $sth->execute();
+        $quote = $sth->fetchrow_hashref();
+    }
+    unless ($quote) {        # if there are not matches, choose a random quote
+        # get a list of all available quote ids
+        $sth = C4::Context->dbh->prepare('SELECT count(*) FROM quotes;');
+        $sth->execute;
+        my $range = ($sth->fetchrow_array)[0];
+        if ($range > 1) {
+            # chose a random id within that range if there is more than one quote
+            my $id = int(rand($range));
+            # grab it
+            $query = 'SELECT * FROM quotes WHERE id = ?;';
+            $sth = C4::Context->dbh->prepare($query);
+            $sth->execute($id);
+        }
+        else {
+            $query = 'SELECT * FROM quotes;';
+            $sth = C4::Context->dbh->prepare($query);
+            $sth->execute();
+        }
+        $quote = $sth->fetchrow_hashref();
+        # update the timestamp for that quote
+        $query = 'UPDATE quotes SET timestamp = ? WHERE id = ?';
+        $sth = C4::Context->dbh->prepare($query);
+        $sth->execute(
+            DateTime::Format::MySQL->format_datetime( dt_from_string() ),
+            $quote->{'id'}
+        );
+    }
+    return $quote;
+}
+
 sub _normalize_match_point {
     my $match_point = shift;
     (my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;