Merge remote-tracking branch 'origin/new/bug_6894'
[koha.git] / C4 / Context.pm
1 package C4::Context;
2 # Copyright 2002 Katipo Communications
3 #
4 # This file is part of Koha.
5 #
6 # Koha is free software; you can redistribute it and/or modify it under the
7 # terms of the GNU General Public License as published by the Free Software
8 # Foundation; either version 2 of the License, or (at your option) any later
9 # version.
10 #
11 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
12 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along
16 # with Koha; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19 use strict;
20 use warnings;
21 use vars qw($VERSION $AUTOLOAD $context @context_stack);
22
23 BEGIN {
24         if ($ENV{'HTTP_USER_AGENT'})    {
25                 require CGI::Carp;
26         # FIXME for future reference, CGI::Carp doc says
27         #  "Note that fatalsToBrowser does not work with mod_perl version 2.0 and higher."
28                 import CGI::Carp qw(fatalsToBrowser);
29                         sub handle_errors {
30                             my $msg = shift;
31                             my $debug_level;
32                             eval {C4::Context->dbh();};
33                             if ($@){
34                                 $debug_level = 1;
35                             } 
36                             else {
37                                 $debug_level =  C4::Context->preference("DebugLevel");
38                             }
39
40                 print q(<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
41                             "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
42                        <html lang="en" xml:lang="en"  xmlns="http://www.w3.org/1999/xhtml">
43                        <head><title>Koha Error</title></head>
44                        <body>
45                 );
46                                 if ($debug_level eq "2"){
47                                         # debug 2 , print extra info too.
48                                         my %versions = get_versions();
49
50                 # a little example table with various version info";
51                                         print "
52                                                 <h1>Koha error</h1>
53                                                 <p>The following fatal error has occurred:</p> 
54                         <pre><code>$msg</code></pre>
55                                                 <table>
56                                                 <tr><th>Apache</th><td>  $versions{apacheVersion}</td></tr>
57                                                 <tr><th>Koha</th><td>    $versions{kohaVersion}</td></tr>
58                                                 <tr><th>Koha DB</th><td> $versions{kohaDbVersion}</td></tr>
59                                                 <tr><th>MySQL</th><td>   $versions{mysqlVersion}</td></tr>
60                                                 <tr><th>OS</th><td>      $versions{osVersion}</td></tr>
61                                                 <tr><th>Perl</th><td>    $versions{perlVersion}</td></tr>
62                                                 </table>";
63
64                                 } elsif ($debug_level eq "1"){
65                                         print "
66                                                 <h1>Koha error</h1>
67                                                 <p>The following fatal error has occurred:</p> 
68                         <pre><code>$msg</code></pre>";
69                                 } else {
70                                         print "<p>production mode - trapped fatal error</p>";
71                                 }       
72                 print "</body></html>";
73                         }
74                 #CGI::Carp::set_message(\&handle_errors);
75                 ## give a stack backtrace if KOHA_BACKTRACES is set
76                 ## can't rely on DebugLevel for this, as we're not yet connected
77                 if ($ENV{KOHA_BACKTRACES}) {
78                         $main::SIG{__DIE__} = \&CGI::Carp::confess;
79                 }
80     }   # else there is no browser to send fatals to!
81         $VERSION = '3.00.00.036';
82 }
83
84 use DBI;
85 use ZOOM;
86 use XML::Simple;
87 use C4::Boolean;
88 use C4::Debug;
89 use POSIX ();
90
91 =head1 NAME
92
93 C4::Context - Maintain and manipulate the context of a Koha script
94
95 =head1 SYNOPSIS
96
97   use C4::Context;
98
99   use C4::Context("/path/to/koha-conf.xml");
100
101   $config_value = C4::Context->config("config_variable");
102
103   $koha_preference = C4::Context->preference("preference");
104
105   $db_handle = C4::Context->dbh;
106
107   $Zconn = C4::Context->Zconn;
108
109   $stopwordhash = C4::Context->stopwords;
110
111 =head1 DESCRIPTION
112
113 When a Koha script runs, it makes use of a certain number of things:
114 configuration settings in F</etc/koha/koha-conf.xml>, a connection to the Koha
115 databases, and so forth. These things make up the I<context> in which
116 the script runs.
117
118 This module takes care of setting up the context for a script:
119 figuring out which configuration file to load, and loading it, opening
120 a connection to the right database, and so forth.
121
122 Most scripts will only use one context. They can simply have
123
124   use C4::Context;
125
126 at the top.
127
128 Other scripts may need to use several contexts. For instance, if a
129 library has two databases, one for a certain collection, and the other
130 for everything else, it might be necessary for a script to use two
131 different contexts to search both databases. Such scripts should use
132 the C<&set_context> and C<&restore_context> functions, below.
133
134 By default, C4::Context reads the configuration from
135 F</etc/koha/koha-conf.xml>. This may be overridden by setting the C<$KOHA_CONF>
136 environment variable to the pathname of a configuration file to use.
137
138 =head1 METHODS
139
140 =cut
141
142 #'
143 # In addition to what is said in the POD above, a Context object is a
144 # reference-to-hash with the following fields:
145 #
146 # config
147 #    A reference-to-hash whose keys and values are the
148 #    configuration variables and values specified in the config
149 #    file (/etc/koha/koha-conf.xml).
150 # dbh
151 #    A handle to the appropriate database for this context.
152 # dbh_stack
153 #    Used by &set_dbh and &restore_dbh to hold other database
154 #    handles for this context.
155 # Zconn
156 #     A connection object for the Zebra server
157
158 # Koha's main configuration file koha-conf.xml
159 # is searched for according to this priority list:
160 #
161 # 1. Path supplied via use C4::Context '/path/to/koha-conf.xml'
162 # 2. Path supplied in KOHA_CONF environment variable.
163 # 3. Path supplied in INSTALLED_CONFIG_FNAME, as long
164 #    as value has changed from its default of 
165 #    '__KOHA_CONF_DIR__/koha-conf.xml', as happens
166 #    when Koha is installed in 'standard' or 'single'
167 #    mode.
168 # 4. Path supplied in CONFIG_FNAME.
169 #
170 # The first entry that refers to a readable file is used.
171
172 use constant CONFIG_FNAME => "/etc/koha/koha-conf.xml";
173                 # Default config file, if none is specified
174                 
175 my $INSTALLED_CONFIG_FNAME = '__KOHA_CONF_DIR__/koha-conf.xml';
176                 # path to config file set by installer
177                 # __KOHA_CONF_DIR__ is set by rewrite-confg.PL
178                 # when Koha is installed in 'standard' or 'single'
179                 # mode.  If Koha was installed in 'dev' mode, 
180                 # __KOHA_CONF_DIR__ is *not* rewritten; instead
181                 # developers should set the KOHA_CONF environment variable 
182
183 $context = undef;        # Initially, no context is set
184 @context_stack = ();        # Initially, no saved contexts
185
186
187 =head2 KOHAVERSION
188
189 returns the kohaversion stored in kohaversion.pl file
190
191 =cut
192
193 sub KOHAVERSION {
194     my $cgidir = C4::Context->intranetdir;
195
196     # Apparently the GIT code does not run out of a CGI-BIN subdirectory
197     # but distribution code does?  (Stan, 1jan08)
198     if(-d $cgidir . "/cgi-bin"){
199         my $cgidir .= "/cgi-bin";
200     }
201     
202     do $cgidir."/kohaversion.pl" || die "NO $cgidir/kohaversion.pl";
203     return kohaversion();
204 }
205 =head2 read_config_file
206
207 Reads the specified Koha config file. 
208
209 Returns an object containing the configuration variables. The object's
210 structure is a bit complex to the uninitiated ... take a look at the
211 koha-conf.xml file as well as the XML::Simple documentation for details. Or,
212 here are a few examples that may give you what you need:
213
214 The simple elements nested within the <config> element:
215
216     my $pass = $koha->{'config'}->{'pass'};
217
218 The <listen> elements:
219
220     my $listen = $koha->{'listen'}->{'biblioserver'}->{'content'};
221
222 The elements nested within the <server> element:
223
224     my $ccl2rpn = $koha->{'server'}->{'biblioserver'}->{'cql2rpn'};
225
226 Returns undef in case of error.
227
228 =cut
229
230 sub read_config_file {          # Pass argument naming config file to read
231     my $koha = XMLin(shift, keyattr => ['id'], forcearray => ['listen', 'server', 'serverinfo'], suppressempty => '');
232     return $koha;                       # Return value: ref-to-hash holding the configuration
233 }
234
235 # db_scheme2dbi
236 # Translates the full text name of a database into de appropiate dbi name
237
238 sub db_scheme2dbi {
239     my $name = shift;
240     # for instance, we support only mysql, so don't care checking
241     return "mysql";
242     for ($name) {
243 # FIXME - Should have other databases. 
244         if (/mysql/) { return("mysql"); }
245         if (/Postgres|Pg|PostgresSQL/) { return("Pg"); }
246         if (/oracle/) { return("Oracle"); }
247     }
248     return undef;         # Just in case
249 }
250
251 sub import {
252     # Create the default context ($C4::Context::Context)
253     # the first time the module is called
254     # (a config file can be optionaly passed)
255
256     # default context allready exists? 
257     return if $context;
258
259     # no ? so load it!
260     my ($pkg,$config_file) = @_ ;
261     my $new_ctx = __PACKAGE__->new($config_file);
262     return unless $new_ctx;
263
264     # if successfully loaded, use it by default
265     $new_ctx->set_context;
266     1;
267 }
268
269 =head2 new
270
271   $context = new C4::Context;
272   $context = new C4::Context("/path/to/koha-conf.xml");
273
274 Allocates a new context. Initializes the context from the specified
275 file, which defaults to either the file given by the C<$KOHA_CONF>
276 environment variable, or F</etc/koha/koha-conf.xml>.
277
278 C<&new> does not set this context as the new default context; for
279 that, use C<&set_context>.
280
281 =cut
282
283 #'
284 # Revision History:
285 # 2004-08-10 A. Tarallo: Added check if the conf file is not empty
286 sub new {
287     my $class = shift;
288     my $conf_fname = shift;        # Config file to load
289     my $self = {};
290
291     # check that the specified config file exists and is not empty
292     undef $conf_fname unless 
293         (defined $conf_fname && -s $conf_fname);
294     # Figure out a good config file to load if none was specified.
295     if (!defined($conf_fname))
296     {
297         # If the $KOHA_CONF environment variable is set, use
298         # that. Otherwise, use the built-in default.
299         if (exists $ENV{"KOHA_CONF"} and $ENV{'KOHA_CONF'} and -s  $ENV{"KOHA_CONF"}) {
300             $conf_fname = $ENV{"KOHA_CONF"};
301         } elsif ($INSTALLED_CONFIG_FNAME !~ /__KOHA_CONF_DIR/ and -s $INSTALLED_CONFIG_FNAME) {
302             # NOTE: be careful -- don't change __KOHA_CONF_DIR in the above
303             # regex to anything else -- don't want installer to rewrite it
304             $conf_fname = $INSTALLED_CONFIG_FNAME;
305         } elsif (-s CONFIG_FNAME) {
306             $conf_fname = CONFIG_FNAME;
307         } else {
308             warn "unable to locate Koha configuration file koha-conf.xml";
309             return undef;
310         }
311     }
312         # Load the desired config file.
313     $self = read_config_file($conf_fname);
314     $self->{"config_file"} = $conf_fname;
315     
316     warn "read_config_file($conf_fname) returned undef" if !defined($self->{"config"});
317     return undef if !defined($self->{"config"});
318
319     $self->{"dbh"} = undef;        # Database handle
320     $self->{"Zconn"} = undef;    # Zebra Connections
321     $self->{"stopwords"} = undef; # stopwords list
322     $self->{"marcfromkohafield"} = undef; # the hash with relations between koha table fields and MARC field/subfield
323     $self->{"userenv"} = undef;        # User env
324     $self->{"activeuser"} = undef;        # current active user
325     $self->{"shelves"} = undef;
326
327     bless $self, $class;
328     return $self;
329 }
330
331 =head2 set_context
332
333   $context = new C4::Context;
334   $context->set_context();
335 or
336   set_context C4::Context $context;
337
338   ...
339   restore_context C4::Context;
340
341 In some cases, it might be necessary for a script to use multiple
342 contexts. C<&set_context> saves the current context on a stack, then
343 sets the context to C<$context>, which will be used in future
344 operations. To restore the previous context, use C<&restore_context>.
345
346 =cut
347
348 #'
349 sub set_context
350 {
351     my $self = shift;
352     my $new_context;    # The context to set
353
354     # Figure out whether this is a class or instance method call.
355     #
356     # We're going to make the assumption that control got here
357     # through valid means, i.e., that the caller used an instance
358     # or class method call, and that control got here through the
359     # usual inheritance mechanisms. The caller can, of course,
360     # break this assumption by playing silly buggers, but that's
361     # harder to do than doing it properly, and harder to check
362     # for.
363     if (ref($self) eq "")
364     {
365         # Class method. The new context is the next argument.
366         $new_context = shift;
367     } else {
368         # Instance method. The new context is $self.
369         $new_context = $self;
370     }
371
372     # Save the old context, if any, on the stack
373     push @context_stack, $context if defined($context);
374
375     # Set the new context
376     $context = $new_context;
377 }
378
379 =head2 restore_context
380
381   &restore_context;
382
383 Restores the context set by C<&set_context>.
384
385 =cut
386
387 #'
388 sub restore_context
389 {
390     my $self = shift;
391
392     if ($#context_stack < 0)
393     {
394         # Stack underflow.
395         die "Context stack underflow";
396     }
397
398     # Pop the old context and set it.
399     $context = pop @context_stack;
400
401     # FIXME - Should this return something, like maybe the context
402     # that was current when this was called?
403 }
404
405 =head2 config
406
407   $value = C4::Context->config("config_variable");
408
409   $value = C4::Context->config_variable;
410
411 Returns the value of a variable specified in the configuration file
412 from which the current context was created.
413
414 The second form is more compact, but of course may conflict with
415 method names. If there is a configuration variable called "new", then
416 C<C4::Config-E<gt>new> will not return it.
417
418 =cut
419
420 sub _common_config ($$) {
421         my $var = shift;
422         my $term = shift;
423     return undef if !defined($context->{$term});
424        # Presumably $self->{$term} might be
425        # undefined if the config file given to &new
426        # didn't exist, and the caller didn't bother
427        # to check the return value.
428
429     # Return the value of the requested config variable
430     return $context->{$term}->{$var};
431 }
432
433 sub config {
434         return _common_config($_[1],'config');
435 }
436 sub zebraconfig {
437         return _common_config($_[1],'server');
438 }
439 sub ModZebrations {
440         return _common_config($_[1],'serverinfo');
441 }
442
443 =head2 preference
444
445   $sys_preference = C4::Context->preference('some_variable');
446
447 Looks up the value of the given system preference in the
448 systempreferences table of the Koha database, and returns it. If the
449 variable is not set or does not exist, undef is returned.
450
451 In case of an error, this may return 0.
452
453 Note: It is impossible to tell the difference between system
454 preferences which do not exist, and those whose values are set to NULL
455 with this method.
456
457 =cut
458
459 # FIXME: running this under mod_perl will require a means of
460 # flushing the caching mechanism.
461
462 my %sysprefs;
463
464 sub preference {
465     my $self = shift;
466     my $var  = shift;                          # The system preference to return
467
468     if (exists $sysprefs{$var}) {
469         return $sysprefs{$var};
470     }
471
472     my $dbh  = C4::Context->dbh or return 0;
473
474     # Look up systempreferences.variable==$var
475     my $sql = <<'END_SQL';
476         SELECT    value
477         FROM    systempreferences
478         WHERE    variable=?
479         LIMIT    1
480 END_SQL
481     $sysprefs{$var} = $dbh->selectrow_array( $sql, {}, $var );
482     return $sysprefs{$var};
483 }
484
485 sub boolean_preference ($) {
486     my $self = shift;
487     my $var = shift;        # The system preference to return
488     my $it = preference($self, $var);
489     return defined($it)? C4::Boolean::true_p($it): undef;
490 }
491
492 =head2 clear_syspref_cache
493
494   C4::Context->clear_syspref_cache();
495
496 cleans the internal cache of sysprefs. Please call this method if
497 you update the systempreferences table. Otherwise, your new changes
498 will not be seen by this process.
499
500 =cut
501
502 sub clear_syspref_cache {
503     %sysprefs = ();
504 }
505
506 =head2 set_preference
507
508   C4::Context->set_preference( $variable, $value );
509
510 This updates a preference's value both in the systempreferences table and in
511 the sysprefs cache.
512
513 =cut
514
515 sub set_preference {
516     my $self = shift;
517     my $var = shift;
518     my $value = shift;
519
520     my $dbh = C4::Context->dbh or return 0;
521
522     my $type = $dbh->selectrow_array( "SELECT type FROM systempreferences WHERE variable = ?", {}, $var );
523
524     $value = 0 if ( $type && $type eq 'YesNo' && $value eq '' );
525
526     my $sth = $dbh->prepare( "
527       INSERT INTO systempreferences
528         ( variable, value )
529         VALUES( ?, ? )
530         ON DUPLICATE KEY UPDATE value = VALUES(value)
531     " );
532
533     $sth->execute( $var, $value );
534     $sth->finish;
535 }
536
537 # AUTOLOAD
538 # This implements C4::Config->foo, and simply returns
539 # C4::Context->config("foo"), as described in the documentation for
540 # &config, above.
541
542 # FIXME - Perhaps this should be extended to check &config first, and
543 # then &preference if that fails. OTOH, AUTOLOAD could lead to crappy
544 # code, so it'd probably be best to delete it altogether so as not to
545 # encourage people to use it.
546 sub AUTOLOAD
547 {
548     my $self = shift;
549
550     $AUTOLOAD =~ s/.*:://;        # Chop off the package name,
551                     # leaving only the function name.
552     return $self->config($AUTOLOAD);
553 }
554
555 =head2 Zconn
556
557   $Zconn = C4::Context->Zconn
558
559 Returns a connection to the Zebra database for the current
560 context. If no connection has yet been made, this method 
561 creates one and connects.
562
563 C<$self> 
564
565 C<$server> one of the servers defined in the koha-conf.xml file
566
567 C<$async> whether this is a asynchronous connection
568
569 C<$auth> whether this connection has rw access (1) or just r access (0 or NULL)
570
571
572 =cut
573
574 sub Zconn {
575     my $self=shift;
576     my $server=shift;
577     my $async=shift;
578     my $auth=shift;
579     my $piggyback=shift;
580     my $syntax=shift;
581     if ( defined($context->{"Zconn"}->{$server}) && (0 == $context->{"Zconn"}->{$server}->errcode()) ) {
582         return $context->{"Zconn"}->{$server};
583     # No connection object or it died. Create one.
584     }else {
585         # release resources if we're closing a connection and making a new one
586         # FIXME: this needs to be smarter -- an error due to a malformed query or
587         # a missing index does not necessarily require us to close the connection
588         # and make a new one, particularly for a batch job.  However, at
589         # first glance it does not look like there's a way to easily check
590         # the basic health of a ZOOM::Connection
591         $context->{"Zconn"}->{$server}->destroy() if defined($context->{"Zconn"}->{$server});
592
593         $context->{"Zconn"}->{$server} = &_new_Zconn($server,$async,$auth,$piggyback,$syntax);
594         return $context->{"Zconn"}->{$server};
595     }
596 }
597
598 =head2 _new_Zconn
599
600 $context->{"Zconn"} = &_new_Zconn($server,$async);
601
602 Internal function. Creates a new database connection from the data given in the current context and returns it.
603
604 C<$server> one of the servers defined in the koha-conf.xml file
605
606 C<$async> whether this is a asynchronous connection
607
608 C<$auth> whether this connection has rw access (1) or just r access (0 or NULL)
609
610 =cut
611
612 sub _new_Zconn {
613     my ($server,$async,$auth,$piggyback,$syntax) = @_;
614
615     my $tried=0; # first attempt
616     my $Zconn; # connection object
617     $server = "biblioserver" unless $server;
618     $syntax = "usmarc" unless $syntax;
619
620     my $host = $context->{'listen'}->{$server}->{'content'};
621     my $servername = $context->{"config"}->{$server};
622     my $user = $context->{"serverinfo"}->{$server}->{"user"};
623     my $password = $context->{"serverinfo"}->{$server}->{"password"};
624  $auth = 1 if($user && $password);   
625     retry:
626     eval {
627         # set options
628         my $o = new ZOOM::Options();
629         $o->option(user=>$user) if $auth;
630         $o->option(password=>$password) if $auth;
631         $o->option(async => 1) if $async;
632         $o->option(count => $piggyback) if $piggyback;
633         $o->option(cqlfile=> $context->{"server"}->{$server}->{"cql2rpn"});
634         $o->option(cclfile=> $context->{"serverinfo"}->{$server}->{"ccl2rpn"});
635         $o->option(preferredRecordSyntax => $syntax);
636         $o->option(elementSetName => "F"); # F for 'full' as opposed to B for 'brief'
637         $o->option(databaseName => ($servername?$servername:"biblios"));
638
639         # create a new connection object
640         $Zconn= create ZOOM::Connection($o);
641
642         # forge to server
643         $Zconn->connect($host, 0);
644
645         # check for errors and warn
646         if ($Zconn->errcode() !=0) {
647             warn "something wrong with the connection: ". $Zconn->errmsg();
648         }
649
650     };
651 #     if ($@) {
652 #         # Koha manages the Zebra server -- this doesn't work currently for me because of permissions issues
653 #         # Also, I'm skeptical about whether it's the best approach
654 #         warn "problem with Zebra";
655 #         if ( C4::Context->preference("ManageZebra") ) {
656 #             if ($@->code==10000 && $tried==0) { ##No connection try restarting Zebra
657 #                 $tried=1;
658 #                 warn "trying to restart Zebra";
659 #                 my $res=system("zebrasrv -f $ENV{'KOHA_CONF'} >/koha/log/zebra-error.log");
660 #                 goto "retry";
661 #             } else {
662 #                 warn "Error ", $@->code(), ": ", $@->message(), "\n";
663 #                 $Zconn="error";
664 #                 return $Zconn;
665 #             }
666 #         }
667 #     }
668     return $Zconn;
669 }
670
671 # _new_dbh
672 # Internal helper function (not a method!). This creates a new
673 # database connection from the data given in the current context, and
674 # returns it.
675 sub _new_dbh
676 {
677
678     ## $context
679     ## correct name for db_schme        
680     my $db_driver;
681     if ($context->config("db_scheme")){
682         $db_driver=db_scheme2dbi($context->config("db_scheme"));
683     }else{
684         $db_driver="mysql";
685     }
686
687     my $db_name   = $context->config("database");
688     my $db_host   = $context->config("hostname");
689     my $db_port   = $context->config("port") || '';
690     my $db_user   = $context->config("user");
691     my $db_passwd = $context->config("pass");
692     # MJR added or die here, as we can't work without dbh
693     my $dbh= DBI->connect("DBI:$db_driver:dbname=$db_name;host=$db_host;port=$db_port",
694     $db_user, $db_passwd, {'RaiseError' => $ENV{DEBUG}?1:0 }) or die $DBI::errstr;
695         my $tz = $ENV{TZ};
696     if ( $db_driver eq 'mysql' ) { 
697         # Koha 3.0 is utf-8, so force utf8 communication between mySQL and koha, whatever the mysql default config.
698         # this is better than modifying my.cnf (and forcing all communications to be in utf8)
699         $dbh->{'mysql_enable_utf8'}=1; #enable
700         $dbh->do("set NAMES 'utf8'");
701         ($tz) and $dbh->do(qq(SET time_zone = "$tz"));
702     }
703     elsif ( $db_driver eq 'Pg' ) {
704             $dbh->do( "set client_encoding = 'UTF8';" );
705         ($tz) and $dbh->do(qq(SET TIME ZONE = "$tz"));
706     }
707     return $dbh;
708 }
709
710 =head2 dbh
711
712   $dbh = C4::Context->dbh;
713
714 Returns a database handle connected to the Koha database for the
715 current context. If no connection has yet been made, this method
716 creates one, and connects to the database.
717
718 This database handle is cached for future use: if you call
719 C<C4::Context-E<gt>dbh> twice, you will get the same handle both
720 times. If you need a second database handle, use C<&new_dbh> and
721 possibly C<&set_dbh>.
722
723 =cut
724
725 #'
726 sub dbh
727 {
728     my $self = shift;
729     my $sth;
730
731     if (defined($context->{"dbh"}) && $context->{"dbh"}->ping()) {
732         return $context->{"dbh"};
733     }
734
735     # No database handle or it died . Create one.
736     $context->{"dbh"} = &_new_dbh();
737
738     return $context->{"dbh"};
739 }
740
741 =head2 new_dbh
742
743   $dbh = C4::Context->new_dbh;
744
745 Creates a new connection to the Koha database for the current context,
746 and returns the database handle (a C<DBI::db> object).
747
748 The handle is not saved anywhere: this method is strictly a
749 convenience function; the point is that it knows which database to
750 connect to so that the caller doesn't have to know.
751
752 =cut
753
754 #'
755 sub new_dbh
756 {
757     my $self = shift;
758
759     return &_new_dbh();
760 }
761
762 =head2 set_dbh
763
764   $my_dbh = C4::Connect->new_dbh;
765   C4::Connect->set_dbh($my_dbh);
766   ...
767   C4::Connect->restore_dbh;
768
769 C<&set_dbh> and C<&restore_dbh> work in a manner analogous to
770 C<&set_context> and C<&restore_context>.
771
772 C<&set_dbh> saves the current database handle on a stack, then sets
773 the current database handle to C<$my_dbh>.
774
775 C<$my_dbh> is assumed to be a good database handle.
776
777 =cut
778
779 #'
780 sub set_dbh
781 {
782     my $self = shift;
783     my $new_dbh = shift;
784
785     # Save the current database handle on the handle stack.
786     # We assume that $new_dbh is all good: if the caller wants to
787     # screw himself by passing an invalid handle, that's fine by
788     # us.
789     push @{$context->{"dbh_stack"}}, $context->{"dbh"};
790     $context->{"dbh"} = $new_dbh;
791 }
792
793 =head2 restore_dbh
794
795   C4::Context->restore_dbh;
796
797 Restores the database handle saved by an earlier call to
798 C<C4::Context-E<gt>set_dbh>.
799
800 =cut
801
802 #'
803 sub restore_dbh
804 {
805     my $self = shift;
806
807     if ($#{$context->{"dbh_stack"}} < 0)
808     {
809         # Stack underflow
810         die "DBH stack underflow";
811     }
812
813     # Pop the old database handle and set it.
814     $context->{"dbh"} = pop @{$context->{"dbh_stack"}};
815
816     # FIXME - If it is determined that restore_context should
817     # return something, then this function should, too.
818 }
819
820 =head2 marcfromkohafield
821
822   $dbh = C4::Context->marcfromkohafield;
823
824 Returns a hash with marcfromkohafield.
825
826 This hash is cached for future use: if you call
827 C<C4::Context-E<gt>marcfromkohafield> twice, you will get the same hash without real DB access
828
829 =cut
830
831 #'
832 sub marcfromkohafield
833 {
834     my $retval = {};
835
836     # If the hash already exists, return it.
837     return $context->{"marcfromkohafield"} if defined($context->{"marcfromkohafield"});
838
839     # No hash. Create one.
840     $context->{"marcfromkohafield"} = &_new_marcfromkohafield();
841
842     return $context->{"marcfromkohafield"};
843 }
844
845 # _new_marcfromkohafield
846 # Internal helper function (not a method!). This creates a new
847 # hash with stopwords
848 sub _new_marcfromkohafield
849 {
850     my $dbh = C4::Context->dbh;
851     my $marcfromkohafield;
852     my $sth = $dbh->prepare("select frameworkcode,kohafield,tagfield,tagsubfield from marc_subfield_structure where kohafield > ''");
853     $sth->execute;
854     while (my ($frameworkcode,$kohafield,$tagfield,$tagsubfield) = $sth->fetchrow) {
855         my $retval = {};
856         $marcfromkohafield->{$frameworkcode}->{$kohafield} = [$tagfield,$tagsubfield];
857     }
858     return $marcfromkohafield;
859 }
860
861 =head2 stopwords
862
863   $dbh = C4::Context->stopwords;
864
865 Returns a hash with stopwords.
866
867 This hash is cached for future use: if you call
868 C<C4::Context-E<gt>stopwords> twice, you will get the same hash without real DB access
869
870 =cut
871
872 #'
873 sub stopwords
874 {
875     my $retval = {};
876
877     # If the hash already exists, return it.
878     return $context->{"stopwords"} if defined($context->{"stopwords"});
879
880     # No hash. Create one.
881     $context->{"stopwords"} = &_new_stopwords();
882
883     return $context->{"stopwords"};
884 }
885
886 # _new_stopwords
887 # Internal helper function (not a method!). This creates a new
888 # hash with stopwords
889 sub _new_stopwords
890 {
891     my $dbh = C4::Context->dbh;
892     my $stopwordlist;
893     my $sth = $dbh->prepare("select word from stopwords");
894     $sth->execute;
895     while (my $stopword = $sth->fetchrow_array) {
896         $stopwordlist->{$stopword} = uc($stopword);
897     }
898     $stopwordlist->{A} = "A" unless $stopwordlist;
899     return $stopwordlist;
900 }
901
902 =head2 userenv
903
904   C4::Context->userenv;
905
906 Retrieves a hash for user environment variables.
907
908 This hash shall be cached for future use: if you call
909 C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
910
911 =cut
912
913 #'
914 sub userenv {
915     my $var = $context->{"activeuser"};
916     return $context->{"userenv"}->{$var} if (defined $var and defined $context->{"userenv"}->{$var});
917     # insecure=1 management
918     if ($context->{"dbh"} && $context->preference('insecure') eq 'yes') {
919         my %insecure;
920         $insecure{flags} = '16382';
921         $insecure{branchname} ='Insecure';
922         $insecure{number} ='0';
923         $insecure{cardnumber} ='0';
924         $insecure{id} = 'insecure';
925         $insecure{branch} = 'INS';
926         $insecure{emailaddress} = 'test@mode.insecure.com';
927         return \%insecure;
928     } else {
929         return;
930     }
931 }
932
933 =head2 set_userenv
934
935   C4::Context->set_userenv($usernum, $userid, $usercnum, $userfirstname, 
936                   $usersurname, $userbranch, $userflags, $emailaddress);
937
938 Establish a hash of user environment variables.
939
940 set_userenv is called in Auth.pm
941
942 =cut
943
944 #'
945 sub set_userenv {
946     my ($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $branchname, $userflags, $emailaddress, $branchprinter)= @_;
947     my $var=$context->{"activeuser"};
948     my $cell = {
949         "number"     => $usernum,
950         "id"         => $userid,
951         "cardnumber" => $usercnum,
952         "firstname"  => $userfirstname,
953         "surname"    => $usersurname,
954         #possibly a law problem
955         "branch"     => $userbranch,
956         "branchname" => $branchname,
957         "flags"      => $userflags,
958         "emailaddress"     => $emailaddress,
959         "branchprinter"    => $branchprinter
960     };
961     $context->{userenv}->{$var} = $cell;
962     return $cell;
963 }
964
965 sub set_shelves_userenv ($$) {
966         my ($type, $shelves) = @_ or return undef;
967         my $activeuser = $context->{activeuser} or return undef;
968         $context->{userenv}->{$activeuser}->{barshelves} = $shelves if $type eq 'bar';
969         $context->{userenv}->{$activeuser}->{pubshelves} = $shelves if $type eq 'pub';
970         $context->{userenv}->{$activeuser}->{totshelves} = $shelves if $type eq 'tot';
971 }
972
973 sub get_shelves_userenv () {
974         my $active;
975         unless ($active = $context->{userenv}->{$context->{activeuser}}) {
976                 $debug and warn "get_shelves_userenv cannot retrieve context->{userenv}->{context->{activeuser}}";
977                 return undef;
978         }
979         my $totshelves = $active->{totshelves} or undef;
980         my $pubshelves = $active->{pubshelves} or undef;
981         my $barshelves = $active->{barshelves} or undef;
982         return ($totshelves, $pubshelves, $barshelves);
983 }
984
985 =head2 _new_userenv
986
987   C4::Context->_new_userenv($session);  # FIXME: This calling style is wrong for what looks like an _internal function
988
989 Builds a hash for user environment variables.
990
991 This hash shall be cached for future use: if you call
992 C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
993
994 _new_userenv is called in Auth.pm
995
996 =cut
997
998 #'
999 sub _new_userenv
1000 {
1001     shift;  # Useless except it compensates for bad calling style
1002     my ($sessionID)= @_;
1003      $context->{"activeuser"}=$sessionID;
1004 }
1005
1006 =head2 _unset_userenv
1007
1008   C4::Context->_unset_userenv;
1009
1010 Destroys the hash for activeuser user environment variables.
1011
1012 =cut
1013
1014 #'
1015
1016 sub _unset_userenv
1017 {
1018     my ($sessionID)= @_;
1019     undef $context->{"activeuser"} if ($context->{"activeuser"} eq $sessionID);
1020 }
1021
1022
1023 =head2 get_versions
1024
1025   C4::Context->get_versions
1026
1027 Gets various version info, for core Koha packages, Currently called from carp handle_errors() sub, to send to browser if 'DebugLevel' syspref is set to '2'.
1028
1029 =cut
1030
1031 #'
1032
1033 # A little example sub to show more debugging info for CGI::Carp
1034 sub get_versions {
1035     my %versions;
1036     $versions{kohaVersion}  = KOHAVERSION();
1037     $versions{kohaDbVersion} = C4::Context->preference('version');
1038     $versions{osVersion} = join(" ", POSIX::uname());
1039     $versions{perlVersion} = $];
1040     {
1041         no warnings qw(exec); # suppress warnings if unable to find a program in $PATH
1042         $versions{mysqlVersion}  = `mysql -V`;
1043         $versions{apacheVersion} = `httpd -v`;
1044         $versions{apacheVersion} = `httpd2 -v`            unless  $versions{apacheVersion} ;
1045         $versions{apacheVersion} = `apache2 -v`           unless  $versions{apacheVersion} ;
1046         $versions{apacheVersion} = `/usr/sbin/apache2 -v` unless  $versions{apacheVersion} ;
1047     }
1048     return %versions;
1049 }
1050
1051
1052 1;
1053 __END__
1054
1055 =head1 ENVIRONMENT
1056
1057 =head2 C<KOHA_CONF>
1058
1059 Specifies the configuration file to read.
1060
1061 =head1 SEE ALSO
1062
1063 XML::Simple
1064
1065 =head1 AUTHORS
1066
1067 Andrew Arensburger <arensb at ooblick dot com>
1068
1069 Joshua Ferraro <jmf at liblime dot com>
1070
1071 =cut