]> git.koha-community.org Git - koha.git/blob - C4/Context.pm
Merge remote branch 'kc/new/enh/bug_5431' into kcmaster
[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
241     for ($name) {
242 # FIXME - Should have other databases. 
243         if (/mysql/i) { return("mysql"); }
244         if (/Postgres|Pg|PostgresSQL/) { return("Pg"); }
245         if (/oracle/i) { return("Oracle"); }
246     }
247     return undef;         # Just in case
248 }
249
250 sub import {
251     # Create the default context ($C4::Context::Context)
252     # the first time the module is called
253     # (a config file can be optionaly passed)
254
255     # default context allready exists? 
256     return if $context;
257
258     # no ? so load it!
259     my ($pkg,$config_file) = @_ ;
260     my $new_ctx = __PACKAGE__->new($config_file);
261     return unless $new_ctx;
262
263     # if successfully loaded, use it by default
264     $new_ctx->set_context;
265     1;
266 }
267
268 =head2 new
269
270   $context = new C4::Context;
271   $context = new C4::Context("/path/to/koha-conf.xml");
272
273 Allocates a new context. Initializes the context from the specified
274 file, which defaults to either the file given by the C<$KOHA_CONF>
275 environment variable, or F</etc/koha/koha-conf.xml>.
276
277 C<&new> does not set this context as the new default context; for
278 that, use C<&set_context>.
279
280 =cut
281
282 #'
283 # Revision History:
284 # 2004-08-10 A. Tarallo: Added check if the conf file is not empty
285 sub new {
286     my $class = shift;
287     my $conf_fname = shift;        # Config file to load
288     my $self = {};
289
290     # check that the specified config file exists and is not empty
291     undef $conf_fname unless 
292         (defined $conf_fname && -s $conf_fname);
293     # Figure out a good config file to load if none was specified.
294     if (!defined($conf_fname))
295     {
296         # If the $KOHA_CONF environment variable is set, use
297         # that. Otherwise, use the built-in default.
298         if (exists $ENV{"KOHA_CONF"} and $ENV{'KOHA_CONF'} and -s  $ENV{"KOHA_CONF"}) {
299             $conf_fname = $ENV{"KOHA_CONF"};
300         } elsif ($INSTALLED_CONFIG_FNAME !~ /__KOHA_CONF_DIR/ and -s $INSTALLED_CONFIG_FNAME) {
301             # NOTE: be careful -- don't change __KOHA_CONF_DIR in the above
302             # regex to anything else -- don't want installer to rewrite it
303             $conf_fname = $INSTALLED_CONFIG_FNAME;
304         } elsif (-s CONFIG_FNAME) {
305             $conf_fname = CONFIG_FNAME;
306         } else {
307             warn "unable to locate Koha configuration file koha-conf.xml";
308             return undef;
309         }
310     }
311         # Load the desired config file.
312     $self = read_config_file($conf_fname);
313     $self->{"config_file"} = $conf_fname;
314     
315     warn "read_config_file($conf_fname) returned undef" if !defined($self->{"config"});
316     return undef if !defined($self->{"config"});
317
318     $self->{"dbh"} = undef;        # Database handle
319     $self->{"Zconn"} = undef;    # Zebra Connections
320     $self->{"stopwords"} = undef; # stopwords list
321     $self->{"marcfromkohafield"} = undef; # the hash with relations between koha table fields and MARC field/subfield
322     $self->{"userenv"} = undef;        # User env
323     $self->{"activeuser"} = undef;        # current active user
324     $self->{"shelves"} = undef;
325
326     bless $self, $class;
327     return $self;
328 }
329
330 =head2 set_context
331
332   $context = new C4::Context;
333   $context->set_context();
334 or
335   set_context C4::Context $context;
336
337   ...
338   restore_context C4::Context;
339
340 In some cases, it might be necessary for a script to use multiple
341 contexts. C<&set_context> saves the current context on a stack, then
342 sets the context to C<$context>, which will be used in future
343 operations. To restore the previous context, use C<&restore_context>.
344
345 =cut
346
347 #'
348 sub set_context
349 {
350     my $self = shift;
351     my $new_context;    # The context to set
352
353     # Figure out whether this is a class or instance method call.
354     #
355     # We're going to make the assumption that control got here
356     # through valid means, i.e., that the caller used an instance
357     # or class method call, and that control got here through the
358     # usual inheritance mechanisms. The caller can, of course,
359     # break this assumption by playing silly buggers, but that's
360     # harder to do than doing it properly, and harder to check
361     # for.
362     if (ref($self) eq "")
363     {
364         # Class method. The new context is the next argument.
365         $new_context = shift;
366     } else {
367         # Instance method. The new context is $self.
368         $new_context = $self;
369     }
370
371     # Save the old context, if any, on the stack
372     push @context_stack, $context if defined($context);
373
374     # Set the new context
375     $context = $new_context;
376 }
377
378 =head2 restore_context
379
380   &restore_context;
381
382 Restores the context set by C<&set_context>.
383
384 =cut
385
386 #'
387 sub restore_context
388 {
389     my $self = shift;
390
391     if ($#context_stack < 0)
392     {
393         # Stack underflow.
394         die "Context stack underflow";
395     }
396
397     # Pop the old context and set it.
398     $context = pop @context_stack;
399
400     # FIXME - Should this return something, like maybe the context
401     # that was current when this was called?
402 }
403
404 =head2 config
405
406   $value = C4::Context->config("config_variable");
407
408   $value = C4::Context->config_variable;
409
410 Returns the value of a variable specified in the configuration file
411 from which the current context was created.
412
413 The second form is more compact, but of course may conflict with
414 method names. If there is a configuration variable called "new", then
415 C<C4::Config-E<gt>new> will not return it.
416
417 =cut
418
419 sub _common_config ($$) {
420         my $var = shift;
421         my $term = shift;
422     return undef if !defined($context->{$term});
423        # Presumably $self->{$term} might be
424        # undefined if the config file given to &new
425        # didn't exist, and the caller didn't bother
426        # to check the return value.
427
428     # Return the value of the requested config variable
429     return $context->{$term}->{$var};
430 }
431
432 sub config {
433         return _common_config($_[1],'config');
434 }
435 sub zebraconfig {
436         return _common_config($_[1],'server');
437 }
438 sub ModZebrations {
439         return _common_config($_[1],'serverinfo');
440 }
441
442 =head2 preference
443
444   $sys_preference = C4::Context->preference('some_variable');
445
446 Looks up the value of the given system preference in the
447 systempreferences table of the Koha database, and returns it. If the
448 variable is not set or does not exist, undef is returned.
449
450 In case of an error, this may return 0.
451
452 Note: It is impossible to tell the difference between system
453 preferences which do not exist, and those whose values are set to NULL
454 with this method.
455
456 =cut
457
458 # FIXME: running this under mod_perl will require a means of
459 # flushing the caching mechanism.
460
461 my %sysprefs;
462
463 sub preference {
464     my $self = shift;
465     my $var  = shift;                          # The system preference to return
466
467     if (exists $sysprefs{$var}) {
468         return $sysprefs{$var};
469     }
470
471     my $dbh  = C4::Context->dbh or return 0;
472
473     # Look up systempreferences.variable==$var
474     my $sql = <<'END_SQL';
475         SELECT    value
476         FROM    systempreferences
477         WHERE    variable=?
478         LIMIT    1
479 END_SQL
480     $sysprefs{$var} = $dbh->selectrow_array( $sql, {}, $var );
481     return $sysprefs{$var};
482 }
483
484 sub boolean_preference ($) {
485     my $self = shift;
486     my $var = shift;        # The system preference to return
487     my $it = preference($self, $var);
488     return defined($it)? C4::Boolean::true_p($it): undef;
489 }
490
491 =head2 clear_syspref_cache
492
493   C4::Context->clear_syspref_cache();
494
495 cleans the internal cache of sysprefs. Please call this method if
496 you update the systempreferences table. Otherwise, your new changes
497 will not be seen by this process.
498
499 =cut
500
501 sub clear_syspref_cache {
502     %sysprefs = ();
503 }
504
505 =head2 set_preference
506
507   C4::Context->set_preference( $variable, $value );
508
509 This updates a preference's value both in the systempreferences table and in
510 the sysprefs cache.
511
512 =cut
513
514 sub set_preference {
515     my $self = shift;
516     my $var = shift;
517     my $value = shift;
518
519     my $dbh = C4::Context->dbh or return 0;
520
521     my $type = $dbh->selectrow_array( "SELECT type FROM systempreferences WHERE variable = ?", {}, $var );
522
523     $value = 0 if ( $type && $type eq 'YesNo' && $value eq '' );
524
525     my $sth = $dbh->prepare( "
526       INSERT INTO systempreferences
527         ( variable, value )
528         VALUES( ?, ? )
529         ON DUPLICATE KEY UPDATE value = VALUES(value)
530     " );
531
532     $sth->execute( $var, $value );
533     $sth->finish;
534 }
535
536 # AUTOLOAD
537 # This implements C4::Config->foo, and simply returns
538 # C4::Context->config("foo"), as described in the documentation for
539 # &config, above.
540
541 # FIXME - Perhaps this should be extended to check &config first, and
542 # then &preference if that fails. OTOH, AUTOLOAD could lead to crappy
543 # code, so it'd probably be best to delete it altogether so as not to
544 # encourage people to use it.
545 sub AUTOLOAD
546 {
547     my $self = shift;
548
549     $AUTOLOAD =~ s/.*:://;        # Chop off the package name,
550                     # leaving only the function name.
551     return $self->config($AUTOLOAD);
552 }
553
554 =head2 Zconn
555
556   $Zconn = C4::Context->Zconn
557
558 Returns a connection to the Zebra database for the current
559 context. If no connection has yet been made, this method 
560 creates one and connects.
561
562 C<$self> 
563
564 C<$server> one of the servers defined in the koha-conf.xml file
565
566 C<$async> whether this is a asynchronous connection
567
568 C<$auth> whether this connection has rw access (1) or just r access (0 or NULL)
569
570
571 =cut
572
573 sub Zconn {
574     my $self=shift;
575     my $server=shift;
576     my $async=shift;
577     my $auth=shift;
578     my $piggyback=shift;
579     my $syntax=shift;
580     if ( defined($context->{"Zconn"}->{$server}) && (0 == $context->{"Zconn"}->{$server}->errcode()) ) {
581         return $context->{"Zconn"}->{$server};
582     # No connection object or it died. Create one.
583     }else {
584         # release resources if we're closing a connection and making a new one
585         # FIXME: this needs to be smarter -- an error due to a malformed query or
586         # a missing index does not necessarily require us to close the connection
587         # and make a new one, particularly for a batch job.  However, at
588         # first glance it does not look like there's a way to easily check
589         # the basic health of a ZOOM::Connection
590         $context->{"Zconn"}->{$server}->destroy() if defined($context->{"Zconn"}->{$server});
591
592         $context->{"Zconn"}->{$server} = &_new_Zconn($server,$async,$auth,$piggyback,$syntax);
593         return $context->{"Zconn"}->{$server};
594     }
595 }
596
597 =head2 _new_Zconn
598
599 $context->{"Zconn"} = &_new_Zconn($server,$async);
600
601 Internal function. Creates a new database connection from the data given in the current context and returns it.
602
603 C<$server> one of the servers defined in the koha-conf.xml file
604
605 C<$async> whether this is a asynchronous connection
606
607 C<$auth> whether this connection has rw access (1) or just r access (0 or NULL)
608
609 =cut
610
611 sub _new_Zconn {
612     my ($server,$async,$auth,$piggyback,$syntax) = @_;
613
614     my $tried=0; # first attempt
615     my $Zconn; # connection object
616     $server = "biblioserver" unless $server;
617     $syntax = "usmarc" unless $syntax;
618
619     my $host = $context->{'listen'}->{$server}->{'content'};
620     my $servername = $context->{"config"}->{$server};
621     my $user = $context->{"serverinfo"}->{$server}->{"user"};
622     my $password = $context->{"serverinfo"}->{$server}->{"password"};
623  $auth = 1 if($user && $password);   
624     retry:
625     eval {
626         # set options
627         my $o = new ZOOM::Options();
628         $o->option(user=>$user) if $auth;
629         $o->option(password=>$password) if $auth;
630         $o->option(async => 1) if $async;
631         $o->option(count => $piggyback) if $piggyback;
632         $o->option(cqlfile=> $context->{"server"}->{$server}->{"cql2rpn"});
633         $o->option(cclfile=> $context->{"serverinfo"}->{$server}->{"ccl2rpn"});
634         $o->option(preferredRecordSyntax => $syntax);
635         $o->option(elementSetName => "F"); # F for 'full' as opposed to B for 'brief'
636         $o->option(databaseName => ($servername?$servername:"biblios"));
637
638         # create a new connection object
639         $Zconn= create ZOOM::Connection($o);
640
641         # forge to server
642         $Zconn->connect($host, 0);
643
644         # check for errors and warn
645         if ($Zconn->errcode() !=0) {
646             warn "something wrong with the connection: ". $Zconn->errmsg();
647         }
648
649     };
650 #     if ($@) {
651 #         # Koha manages the Zebra server -- this doesn't work currently for me because of permissions issues
652 #         # Also, I'm skeptical about whether it's the best approach
653 #         warn "problem with Zebra";
654 #         if ( C4::Context->preference("ManageZebra") ) {
655 #             if ($@->code==10000 && $tried==0) { ##No connection try restarting Zebra
656 #                 $tried=1;
657 #                 warn "trying to restart Zebra";
658 #                 my $res=system("zebrasrv -f $ENV{'KOHA_CONF'} >/koha/log/zebra-error.log");
659 #                 goto "retry";
660 #             } else {
661 #                 warn "Error ", $@->code(), ": ", $@->message(), "\n";
662 #                 $Zconn="error";
663 #                 return $Zconn;
664 #             }
665 #         }
666 #     }
667     return $Zconn;
668 }
669
670 # _new_dbh
671 # Internal helper function (not a method!). This creates a new
672 # database connection from the data given in the current context, and
673 # returns it.
674 sub _new_dbh
675 {
676
677     ## $context
678     ## correct name for db_schme        
679     my $db_driver;
680     if ($context->config("db_scheme")){
681         $db_driver=db_scheme2dbi($context->config("db_scheme"));
682     }else{
683         $db_driver="mysql";
684     }
685
686     my $db_name   = $context->config("database");
687     my $db_host   = $context->config("hostname");
688     my $db_port   = $context->config("port") || '';
689     my $db_user   = $context->config("user");
690     my $db_passwd = $context->config("pass");
691     # MJR added or die here, as we can't work without dbh
692     my $dbh= DBI->connect("DBI:$db_driver:dbname=$db_name;host=$db_host;port=$db_port",
693         $db_user, $db_passwd) or die $DBI::errstr;
694         my $tz = $ENV{TZ};
695     if ( $db_driver eq 'mysql' ) { 
696         # Koha 3.0 is utf-8, so force utf8 communication between mySQL and koha, whatever the mysql default config.
697         # this is better than modifying my.cnf (and forcing all communications to be in utf8)
698         $dbh->{'mysql_enable_utf8'}=1; #enable
699         $dbh->do("set NAMES 'utf8'");
700         ($tz) and $dbh->do(qq(SET time_zone = "$tz"));
701     }
702     elsif ( $db_driver eq 'Pg' ) {
703             $dbh->do( "set client_encoding = 'UTF8';" );
704         ($tz) and $dbh->do(qq(SET TIME ZONE = "$tz"));
705     }
706     return $dbh;
707 }
708
709 =head2 dbh
710
711   $dbh = C4::Context->dbh;
712
713 Returns a database handle connected to the Koha database for the
714 current context. If no connection has yet been made, this method
715 creates one, and connects to the database.
716
717 This database handle is cached for future use: if you call
718 C<C4::Context-E<gt>dbh> twice, you will get the same handle both
719 times. If you need a second database handle, use C<&new_dbh> and
720 possibly C<&set_dbh>.
721
722 =cut
723
724 #'
725 sub dbh
726 {
727     my $self = shift;
728     my $sth;
729
730     if (defined($context->{"dbh"}) && $context->{"dbh"}->ping()) {
731         return $context->{"dbh"};
732     }
733
734     # No database handle or it died . Create one.
735     $context->{"dbh"} = &_new_dbh();
736
737     return $context->{"dbh"};
738 }
739
740 =head2 new_dbh
741
742   $dbh = C4::Context->new_dbh;
743
744 Creates a new connection to the Koha database for the current context,
745 and returns the database handle (a C<DBI::db> object).
746
747 The handle is not saved anywhere: this method is strictly a
748 convenience function; the point is that it knows which database to
749 connect to so that the caller doesn't have to know.
750
751 =cut
752
753 #'
754 sub new_dbh
755 {
756     my $self = shift;
757
758     return &_new_dbh();
759 }
760
761 =head2 set_dbh
762
763   $my_dbh = C4::Connect->new_dbh;
764   C4::Connect->set_dbh($my_dbh);
765   ...
766   C4::Connect->restore_dbh;
767
768 C<&set_dbh> and C<&restore_dbh> work in a manner analogous to
769 C<&set_context> and C<&restore_context>.
770
771 C<&set_dbh> saves the current database handle on a stack, then sets
772 the current database handle to C<$my_dbh>.
773
774 C<$my_dbh> is assumed to be a good database handle.
775
776 =cut
777
778 #'
779 sub set_dbh
780 {
781     my $self = shift;
782     my $new_dbh = shift;
783
784     # Save the current database handle on the handle stack.
785     # We assume that $new_dbh is all good: if the caller wants to
786     # screw himself by passing an invalid handle, that's fine by
787     # us.
788     push @{$context->{"dbh_stack"}}, $context->{"dbh"};
789     $context->{"dbh"} = $new_dbh;
790 }
791
792 =head2 restore_dbh
793
794   C4::Context->restore_dbh;
795
796 Restores the database handle saved by an earlier call to
797 C<C4::Context-E<gt>set_dbh>.
798
799 =cut
800
801 #'
802 sub restore_dbh
803 {
804     my $self = shift;
805
806     if ($#{$context->{"dbh_stack"}} < 0)
807     {
808         # Stack underflow
809         die "DBH stack underflow";
810     }
811
812     # Pop the old database handle and set it.
813     $context->{"dbh"} = pop @{$context->{"dbh_stack"}};
814
815     # FIXME - If it is determined that restore_context should
816     # return something, then this function should, too.
817 }
818
819 =head2 marcfromkohafield
820
821   $dbh = C4::Context->marcfromkohafield;
822
823 Returns a hash with marcfromkohafield.
824
825 This hash is cached for future use: if you call
826 C<C4::Context-E<gt>marcfromkohafield> twice, you will get the same hash without real DB access
827
828 =cut
829
830 #'
831 sub marcfromkohafield
832 {
833     my $retval = {};
834
835     # If the hash already exists, return it.
836     return $context->{"marcfromkohafield"} if defined($context->{"marcfromkohafield"});
837
838     # No hash. Create one.
839     $context->{"marcfromkohafield"} = &_new_marcfromkohafield();
840
841     return $context->{"marcfromkohafield"};
842 }
843
844 # _new_marcfromkohafield
845 # Internal helper function (not a method!). This creates a new
846 # hash with stopwords
847 sub _new_marcfromkohafield
848 {
849     my $dbh = C4::Context->dbh;
850     my $marcfromkohafield;
851     my $sth = $dbh->prepare("select frameworkcode,kohafield,tagfield,tagsubfield from marc_subfield_structure where kohafield > ''");
852     $sth->execute;
853     while (my ($frameworkcode,$kohafield,$tagfield,$tagsubfield) = $sth->fetchrow) {
854         my $retval = {};
855         $marcfromkohafield->{$frameworkcode}->{$kohafield} = [$tagfield,$tagsubfield];
856     }
857     return $marcfromkohafield;
858 }
859
860 =head2 stopwords
861
862   $dbh = C4::Context->stopwords;
863
864 Returns a hash with stopwords.
865
866 This hash is cached for future use: if you call
867 C<C4::Context-E<gt>stopwords> twice, you will get the same hash without real DB access
868
869 =cut
870
871 #'
872 sub stopwords
873 {
874     my $retval = {};
875
876     # If the hash already exists, return it.
877     return $context->{"stopwords"} if defined($context->{"stopwords"});
878
879     # No hash. Create one.
880     $context->{"stopwords"} = &_new_stopwords();
881
882     return $context->{"stopwords"};
883 }
884
885 # _new_stopwords
886 # Internal helper function (not a method!). This creates a new
887 # hash with stopwords
888 sub _new_stopwords
889 {
890     my $dbh = C4::Context->dbh;
891     my $stopwordlist;
892     my $sth = $dbh->prepare("select word from stopwords");
893     $sth->execute;
894     while (my $stopword = $sth->fetchrow_array) {
895         $stopwordlist->{$stopword} = uc($stopword);
896     }
897     $stopwordlist->{A} = "A" unless $stopwordlist;
898     return $stopwordlist;
899 }
900
901 =head2 userenv
902
903   C4::Context->userenv;
904
905 Retrieves a hash for user environment variables.
906
907 This hash shall be cached for future use: if you call
908 C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
909
910 =cut
911
912 #'
913 sub userenv {
914     my $var = $context->{"activeuser"};
915     return $context->{"userenv"}->{$var} if (defined $var and defined $context->{"userenv"}->{$var});
916     # insecure=1 management
917     if ($context->{"dbh"} && $context->preference('insecure') eq 'yes') {
918         my %insecure;
919         $insecure{flags} = '16382';
920         $insecure{branchname} ='Insecure';
921         $insecure{number} ='0';
922         $insecure{cardnumber} ='0';
923         $insecure{id} = 'insecure';
924         $insecure{branch} = 'INS';
925         $insecure{emailaddress} = 'test@mode.insecure.com';
926         return \%insecure;
927     } else {
928         return;
929     }
930 }
931
932 =head2 set_userenv
933
934   C4::Context->set_userenv($usernum, $userid, $usercnum, $userfirstname, 
935                   $usersurname, $userbranch, $userflags, $emailaddress);
936
937 Establish a hash of user environment variables.
938
939 set_userenv is called in Auth.pm
940
941 =cut
942
943 #'
944 sub set_userenv {
945     my ($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $branchname, $userflags, $emailaddress, $branchprinter)= @_;
946     my $var=$context->{"activeuser"};
947     my $cell = {
948         "number"     => $usernum,
949         "id"         => $userid,
950         "cardnumber" => $usercnum,
951         "firstname"  => $userfirstname,
952         "surname"    => $usersurname,
953         #possibly a law problem
954         "branch"     => $userbranch,
955         "branchname" => $branchname,
956         "flags"      => $userflags,
957         "emailaddress"     => $emailaddress,
958         "branchprinter"    => $branchprinter
959     };
960     $context->{userenv}->{$var} = $cell;
961     return $cell;
962 }
963
964 sub set_shelves_userenv ($$) {
965         my ($type, $shelves) = @_ or return undef;
966         my $activeuser = $context->{activeuser} or return undef;
967         $context->{userenv}->{$activeuser}->{barshelves} = $shelves if $type eq 'bar';
968         $context->{userenv}->{$activeuser}->{pubshelves} = $shelves if $type eq 'pub';
969         $context->{userenv}->{$activeuser}->{totshelves} = $shelves if $type eq 'tot';
970 }
971
972 sub get_shelves_userenv () {
973         my $active;
974         unless ($active = $context->{userenv}->{$context->{activeuser}}) {
975                 $debug and warn "get_shelves_userenv cannot retrieve context->{userenv}->{context->{activeuser}}";
976                 return undef;
977         }
978         my $totshelves = $active->{totshelves} or undef;
979         my $pubshelves = $active->{pubshelves} or undef;
980         my $barshelves = $active->{barshelves} or undef;
981         return ($totshelves, $pubshelves, $barshelves);
982 }
983
984 =head2 _new_userenv
985
986   C4::Context->_new_userenv($session);  # FIXME: This calling style is wrong for what looks like an _internal function
987
988 Builds a hash for user environment variables.
989
990 This hash shall be cached for future use: if you call
991 C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
992
993 _new_userenv is called in Auth.pm
994
995 =cut
996
997 #'
998 sub _new_userenv
999 {
1000     shift;  # Useless except it compensates for bad calling style
1001     my ($sessionID)= @_;
1002      $context->{"activeuser"}=$sessionID;
1003 }
1004
1005 =head2 _unset_userenv
1006
1007   C4::Context->_unset_userenv;
1008
1009 Destroys the hash for activeuser user environment variables.
1010
1011 =cut
1012
1013 #'
1014
1015 sub _unset_userenv
1016 {
1017     my ($sessionID)= @_;
1018     undef $context->{"activeuser"} if ($context->{"activeuser"} eq $sessionID);
1019 }
1020
1021
1022 =head2 get_versions
1023
1024   C4::Context->get_versions
1025
1026 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'.
1027
1028 =cut
1029
1030 #'
1031
1032 # A little example sub to show more debugging info for CGI::Carp
1033 sub get_versions {
1034     my %versions;
1035     $versions{kohaVersion}  = KOHAVERSION();
1036     $versions{kohaDbVersion} = C4::Context->preference('version');
1037     $versions{osVersion} = join(" ", POSIX::uname());
1038     $versions{perlVersion} = $];
1039     {
1040         no warnings qw(exec); # suppress warnings if unable to find a program in $PATH
1041         $versions{mysqlVersion}  = `mysql -V`;
1042         $versions{apacheVersion} = `httpd -v`;
1043         $versions{apacheVersion} = `httpd2 -v`            unless  $versions{apacheVersion} ;
1044         $versions{apacheVersion} = `apache2 -v`           unless  $versions{apacheVersion} ;
1045         $versions{apacheVersion} = `/usr/sbin/apache2 -v` unless  $versions{apacheVersion} ;
1046     }
1047     return %versions;
1048 }
1049
1050
1051 1;
1052 __END__
1053
1054 =head1 ENVIRONMENT
1055
1056 =head2 C<KOHA_CONF>
1057
1058 Specifies the configuration file to read.
1059
1060 =head1 SEE ALSO
1061
1062 XML::Simple
1063
1064 =head1 AUTHORS
1065
1066 Andrew Arensburger <arensb at ooblick dot com>
1067
1068 Joshua Ferraro <jmf at liblime dot com>
1069
1070 =cut