Bug 6132: Update sysprefs cache in set_preference
[koha-ffzg.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  = lc(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 = lc(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     if($sth->execute( $var, $value )) {
534         $sysprefs{$var} = $value;
535     }
536     $sth->finish;
537 }
538
539 # AUTOLOAD
540 # This implements C4::Config->foo, and simply returns
541 # C4::Context->config("foo"), as described in the documentation for
542 # &config, above.
543
544 # FIXME - Perhaps this should be extended to check &config first, and
545 # then &preference if that fails. OTOH, AUTOLOAD could lead to crappy
546 # code, so it'd probably be best to delete it altogether so as not to
547 # encourage people to use it.
548 sub AUTOLOAD
549 {
550     my $self = shift;
551
552     $AUTOLOAD =~ s/.*:://;        # Chop off the package name,
553                     # leaving only the function name.
554     return $self->config($AUTOLOAD);
555 }
556
557 =head2 Zconn
558
559   $Zconn = C4::Context->Zconn
560
561 Returns a connection to the Zebra database for the current
562 context. If no connection has yet been made, this method 
563 creates one and connects.
564
565 C<$self> 
566
567 C<$server> one of the servers defined in the koha-conf.xml file
568
569 C<$async> whether this is a asynchronous connection
570
571 C<$auth> whether this connection has rw access (1) or just r access (0 or NULL)
572
573
574 =cut
575
576 sub Zconn {
577     my $self=shift;
578     my $server=shift;
579     my $async=shift;
580     my $auth=shift;
581     my $piggyback=shift;
582     my $syntax=shift;
583     if ( defined($context->{"Zconn"}->{$server}) && (0 == $context->{"Zconn"}->{$server}->errcode()) ) {
584         return $context->{"Zconn"}->{$server};
585     # No connection object or it died. Create one.
586     }else {
587         # release resources if we're closing a connection and making a new one
588         # FIXME: this needs to be smarter -- an error due to a malformed query or
589         # a missing index does not necessarily require us to close the connection
590         # and make a new one, particularly for a batch job.  However, at
591         # first glance it does not look like there's a way to easily check
592         # the basic health of a ZOOM::Connection
593         $context->{"Zconn"}->{$server}->destroy() if defined($context->{"Zconn"}->{$server});
594
595         $context->{"Zconn"}->{$server} = &_new_Zconn($server,$async,$auth,$piggyback,$syntax);
596         return $context->{"Zconn"}->{$server};
597     }
598 }
599
600 =head2 _new_Zconn
601
602 $context->{"Zconn"} = &_new_Zconn($server,$async);
603
604 Internal function. Creates a new database connection from the data given in the current context and returns it.
605
606 C<$server> one of the servers defined in the koha-conf.xml file
607
608 C<$async> whether this is a asynchronous connection
609
610 C<$auth> whether this connection has rw access (1) or just r access (0 or NULL)
611
612 =cut
613
614 sub _new_Zconn {
615     my ($server,$async,$auth,$piggyback,$syntax) = @_;
616
617     my $tried=0; # first attempt
618     my $Zconn; # connection object
619     $server = "biblioserver" unless $server;
620     $syntax = "usmarc" unless $syntax;
621
622     my $host = $context->{'listen'}->{$server}->{'content'};
623     my $servername = $context->{"config"}->{$server};
624     my $user = $context->{"serverinfo"}->{$server}->{"user"};
625     my $password = $context->{"serverinfo"}->{$server}->{"password"};
626  $auth = 1 if($user && $password);   
627     retry:
628     eval {
629         # set options
630         my $o = new ZOOM::Options();
631         $o->option(user=>$user) if $auth;
632         $o->option(password=>$password) if $auth;
633         $o->option(async => 1) if $async;
634         $o->option(count => $piggyback) if $piggyback;
635         $o->option(cqlfile=> $context->{"server"}->{$server}->{"cql2rpn"});
636         $o->option(cclfile=> $context->{"serverinfo"}->{$server}->{"ccl2rpn"});
637         $o->option(preferredRecordSyntax => $syntax);
638         $o->option(elementSetName => "F"); # F for 'full' as opposed to B for 'brief'
639         $o->option(databaseName => ($servername?$servername:"biblios"));
640
641         # create a new connection object
642         $Zconn= create ZOOM::Connection($o);
643
644         # forge to server
645         $Zconn->connect($host, 0);
646
647         # check for errors and warn
648         if ($Zconn->errcode() !=0) {
649             warn "something wrong with the connection: ". $Zconn->errmsg();
650         }
651
652     };
653 #     if ($@) {
654 #         # Koha manages the Zebra server -- this doesn't work currently for me because of permissions issues
655 #         # Also, I'm skeptical about whether it's the best approach
656 #         warn "problem with Zebra";
657 #         if ( C4::Context->preference("ManageZebra") ) {
658 #             if ($@->code==10000 && $tried==0) { ##No connection try restarting Zebra
659 #                 $tried=1;
660 #                 warn "trying to restart Zebra";
661 #                 my $res=system("zebrasrv -f $ENV{'KOHA_CONF'} >/koha/log/zebra-error.log");
662 #                 goto "retry";
663 #             } else {
664 #                 warn "Error ", $@->code(), ": ", $@->message(), "\n";
665 #                 $Zconn="error";
666 #                 return $Zconn;
667 #             }
668 #         }
669 #     }
670     return $Zconn;
671 }
672
673 # _new_dbh
674 # Internal helper function (not a method!). This creates a new
675 # database connection from the data given in the current context, and
676 # returns it.
677 sub _new_dbh
678 {
679
680     ## $context
681     ## correct name for db_schme        
682     my $db_driver;
683     if ($context->config("db_scheme")){
684         $db_driver=db_scheme2dbi($context->config("db_scheme"));
685     }else{
686         $db_driver="mysql";
687     }
688
689     my $db_name   = $context->config("database");
690     my $db_host   = $context->config("hostname");
691     my $db_port   = $context->config("port") || '';
692     my $db_user   = $context->config("user");
693     my $db_passwd = $context->config("pass");
694     # MJR added or die here, as we can't work without dbh
695     my $dbh= DBI->connect("DBI:$db_driver:dbname=$db_name;host=$db_host;port=$db_port",
696     $db_user, $db_passwd, {'RaiseError' => $ENV{DEBUG}?1:0 }) or die $DBI::errstr;
697         my $tz = $ENV{TZ};
698     if ( $db_driver eq 'mysql' ) { 
699         # Koha 3.0 is utf-8, so force utf8 communication between mySQL and koha, whatever the mysql default config.
700         # this is better than modifying my.cnf (and forcing all communications to be in utf8)
701         $dbh->{'mysql_enable_utf8'}=1; #enable
702         $dbh->do("set NAMES 'utf8'");
703         ($tz) and $dbh->do(qq(SET time_zone = "$tz"));
704     }
705     elsif ( $db_driver eq 'Pg' ) {
706             $dbh->do( "set client_encoding = 'UTF8';" );
707         ($tz) and $dbh->do(qq(SET TIME ZONE = "$tz"));
708     }
709     return $dbh;
710 }
711
712 =head2 dbh
713
714   $dbh = C4::Context->dbh;
715
716 Returns a database handle connected to the Koha database for the
717 current context. If no connection has yet been made, this method
718 creates one, and connects to the database.
719
720 This database handle is cached for future use: if you call
721 C<C4::Context-E<gt>dbh> twice, you will get the same handle both
722 times. If you need a second database handle, use C<&new_dbh> and
723 possibly C<&set_dbh>.
724
725 =cut
726
727 #'
728 sub dbh
729 {
730     my $self = shift;
731     my $sth;
732
733     if (defined($context->{"dbh"}) && $context->{"dbh"}->ping()) {
734         return $context->{"dbh"};
735     }
736
737     # No database handle or it died . Create one.
738     $context->{"dbh"} = &_new_dbh();
739
740     return $context->{"dbh"};
741 }
742
743 =head2 new_dbh
744
745   $dbh = C4::Context->new_dbh;
746
747 Creates a new connection to the Koha database for the current context,
748 and returns the database handle (a C<DBI::db> object).
749
750 The handle is not saved anywhere: this method is strictly a
751 convenience function; the point is that it knows which database to
752 connect to so that the caller doesn't have to know.
753
754 =cut
755
756 #'
757 sub new_dbh
758 {
759     my $self = shift;
760
761     return &_new_dbh();
762 }
763
764 =head2 set_dbh
765
766   $my_dbh = C4::Connect->new_dbh;
767   C4::Connect->set_dbh($my_dbh);
768   ...
769   C4::Connect->restore_dbh;
770
771 C<&set_dbh> and C<&restore_dbh> work in a manner analogous to
772 C<&set_context> and C<&restore_context>.
773
774 C<&set_dbh> saves the current database handle on a stack, then sets
775 the current database handle to C<$my_dbh>.
776
777 C<$my_dbh> is assumed to be a good database handle.
778
779 =cut
780
781 #'
782 sub set_dbh
783 {
784     my $self = shift;
785     my $new_dbh = shift;
786
787     # Save the current database handle on the handle stack.
788     # We assume that $new_dbh is all good: if the caller wants to
789     # screw himself by passing an invalid handle, that's fine by
790     # us.
791     push @{$context->{"dbh_stack"}}, $context->{"dbh"};
792     $context->{"dbh"} = $new_dbh;
793 }
794
795 =head2 restore_dbh
796
797   C4::Context->restore_dbh;
798
799 Restores the database handle saved by an earlier call to
800 C<C4::Context-E<gt>set_dbh>.
801
802 =cut
803
804 #'
805 sub restore_dbh
806 {
807     my $self = shift;
808
809     if ($#{$context->{"dbh_stack"}} < 0)
810     {
811         # Stack underflow
812         die "DBH stack underflow";
813     }
814
815     # Pop the old database handle and set it.
816     $context->{"dbh"} = pop @{$context->{"dbh_stack"}};
817
818     # FIXME - If it is determined that restore_context should
819     # return something, then this function should, too.
820 }
821
822 =head2 marcfromkohafield
823
824   $dbh = C4::Context->marcfromkohafield;
825
826 Returns a hash with marcfromkohafield.
827
828 This hash is cached for future use: if you call
829 C<C4::Context-E<gt>marcfromkohafield> twice, you will get the same hash without real DB access
830
831 =cut
832
833 #'
834 sub marcfromkohafield
835 {
836     my $retval = {};
837
838     # If the hash already exists, return it.
839     return $context->{"marcfromkohafield"} if defined($context->{"marcfromkohafield"});
840
841     # No hash. Create one.
842     $context->{"marcfromkohafield"} = &_new_marcfromkohafield();
843
844     return $context->{"marcfromkohafield"};
845 }
846
847 # _new_marcfromkohafield
848 # Internal helper function (not a method!). This creates a new
849 # hash with stopwords
850 sub _new_marcfromkohafield
851 {
852     my $dbh = C4::Context->dbh;
853     my $marcfromkohafield;
854     my $sth = $dbh->prepare("select frameworkcode,kohafield,tagfield,tagsubfield from marc_subfield_structure where kohafield > ''");
855     $sth->execute;
856     while (my ($frameworkcode,$kohafield,$tagfield,$tagsubfield) = $sth->fetchrow) {
857         my $retval = {};
858         $marcfromkohafield->{$frameworkcode}->{$kohafield} = [$tagfield,$tagsubfield];
859     }
860     return $marcfromkohafield;
861 }
862
863 =head2 stopwords
864
865   $dbh = C4::Context->stopwords;
866
867 Returns a hash with stopwords.
868
869 This hash is cached for future use: if you call
870 C<C4::Context-E<gt>stopwords> twice, you will get the same hash without real DB access
871
872 =cut
873
874 #'
875 sub stopwords
876 {
877     my $retval = {};
878
879     # If the hash already exists, return it.
880     return $context->{"stopwords"} if defined($context->{"stopwords"});
881
882     # No hash. Create one.
883     $context->{"stopwords"} = &_new_stopwords();
884
885     return $context->{"stopwords"};
886 }
887
888 # _new_stopwords
889 # Internal helper function (not a method!). This creates a new
890 # hash with stopwords
891 sub _new_stopwords
892 {
893     my $dbh = C4::Context->dbh;
894     my $stopwordlist;
895     my $sth = $dbh->prepare("select word from stopwords");
896     $sth->execute;
897     while (my $stopword = $sth->fetchrow_array) {
898         $stopwordlist->{$stopword} = uc($stopword);
899     }
900     $stopwordlist->{A} = "A" unless $stopwordlist;
901     return $stopwordlist;
902 }
903
904 =head2 userenv
905
906   C4::Context->userenv;
907
908 Retrieves a hash for user environment variables.
909
910 This hash shall be cached for future use: if you call
911 C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
912
913 =cut
914
915 #'
916 sub userenv {
917     my $var = $context->{"activeuser"};
918     return $context->{"userenv"}->{$var} if (defined $var and defined $context->{"userenv"}->{$var});
919     # insecure=1 management
920     if ($context->{"dbh"} && $context->preference('insecure') eq 'yes') {
921         my %insecure;
922         $insecure{flags} = '16382';
923         $insecure{branchname} ='Insecure';
924         $insecure{number} ='0';
925         $insecure{cardnumber} ='0';
926         $insecure{id} = 'insecure';
927         $insecure{branch} = 'INS';
928         $insecure{emailaddress} = 'test@mode.insecure.com';
929         return \%insecure;
930     } else {
931         return;
932     }
933 }
934
935 =head2 set_userenv
936
937   C4::Context->set_userenv($usernum, $userid, $usercnum, $userfirstname, 
938                   $usersurname, $userbranch, $userflags, $emailaddress);
939
940 Establish a hash of user environment variables.
941
942 set_userenv is called in Auth.pm
943
944 =cut
945
946 #'
947 sub set_userenv {
948     my ($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $branchname, $userflags, $emailaddress, $branchprinter)= @_;
949     my $var=$context->{"activeuser"};
950     my $cell = {
951         "number"     => $usernum,
952         "id"         => $userid,
953         "cardnumber" => $usercnum,
954         "firstname"  => $userfirstname,
955         "surname"    => $usersurname,
956         #possibly a law problem
957         "branch"     => $userbranch,
958         "branchname" => $branchname,
959         "flags"      => $userflags,
960         "emailaddress"     => $emailaddress,
961         "branchprinter"    => $branchprinter
962     };
963     $context->{userenv}->{$var} = $cell;
964     return $cell;
965 }
966
967 sub set_shelves_userenv ($$) {
968         my ($type, $shelves) = @_ or return undef;
969         my $activeuser = $context->{activeuser} or return undef;
970         $context->{userenv}->{$activeuser}->{barshelves} = $shelves if $type eq 'bar';
971         $context->{userenv}->{$activeuser}->{pubshelves} = $shelves if $type eq 'pub';
972         $context->{userenv}->{$activeuser}->{totshelves} = $shelves if $type eq 'tot';
973 }
974
975 sub get_shelves_userenv () {
976         my $active;
977         unless ($active = $context->{userenv}->{$context->{activeuser}}) {
978                 $debug and warn "get_shelves_userenv cannot retrieve context->{userenv}->{context->{activeuser}}";
979                 return undef;
980         }
981         my $totshelves = $active->{totshelves} or undef;
982         my $pubshelves = $active->{pubshelves} or undef;
983         my $barshelves = $active->{barshelves} or undef;
984         return ($totshelves, $pubshelves, $barshelves);
985 }
986
987 =head2 _new_userenv
988
989   C4::Context->_new_userenv($session);  # FIXME: This calling style is wrong for what looks like an _internal function
990
991 Builds a hash for user environment variables.
992
993 This hash shall be cached for future use: if you call
994 C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
995
996 _new_userenv is called in Auth.pm
997
998 =cut
999
1000 #'
1001 sub _new_userenv
1002 {
1003     shift;  # Useless except it compensates for bad calling style
1004     my ($sessionID)= @_;
1005      $context->{"activeuser"}=$sessionID;
1006 }
1007
1008 =head2 _unset_userenv
1009
1010   C4::Context->_unset_userenv;
1011
1012 Destroys the hash for activeuser user environment variables.
1013
1014 =cut
1015
1016 #'
1017
1018 sub _unset_userenv
1019 {
1020     my ($sessionID)= @_;
1021     undef $context->{"activeuser"} if ($context->{"activeuser"} eq $sessionID);
1022 }
1023
1024
1025 =head2 get_versions
1026
1027   C4::Context->get_versions
1028
1029 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'.
1030
1031 =cut
1032
1033 #'
1034
1035 # A little example sub to show more debugging info for CGI::Carp
1036 sub get_versions {
1037     my %versions;
1038     $versions{kohaVersion}  = KOHAVERSION();
1039     $versions{kohaDbVersion} = C4::Context->preference('version');
1040     $versions{osVersion} = join(" ", POSIX::uname());
1041     $versions{perlVersion} = $];
1042     {
1043         no warnings qw(exec); # suppress warnings if unable to find a program in $PATH
1044         $versions{mysqlVersion}  = `mysql -V`;
1045         $versions{apacheVersion} = `httpd -v`;
1046         $versions{apacheVersion} = `httpd2 -v`            unless  $versions{apacheVersion} ;
1047         $versions{apacheVersion} = `apache2 -v`           unless  $versions{apacheVersion} ;
1048         $versions{apacheVersion} = `/usr/sbin/apache2 -v` unless  $versions{apacheVersion} ;
1049     }
1050     return %versions;
1051 }
1052
1053
1054 1;
1055 __END__
1056
1057 =head1 ENVIRONMENT
1058
1059 =head2 C<KOHA_CONF>
1060
1061 Specifies the configuration file to read.
1062
1063 =head1 SEE ALSO
1064
1065 XML::Simple
1066
1067 =head1 AUTHORS
1068
1069 Andrew Arensburger <arensb at ooblick dot com>
1070
1071 Joshua Ferraro <jmf at liblime dot com>
1072
1073 =cut