bug fixed: utf-8 data where not displayed correctly in screens. Supposing
[koha.git] / C4 / Context.pm
1 # Copyright 2002 Katipo Communications
2 #
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation; either version 2 of the License, or (at your option) any later
8 # version.
9 #
10 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License along with
15 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
16 # Suite 330, Boston, MA  02111-1307 USA
17
18 # $Id$
19
20 package C4::Context;
21 use strict;
22 use DBI;
23 use C4::Boolean;
24
25 use vars qw($VERSION $AUTOLOAD),
26         qw($context),
27         qw(@context_stack);
28
29 $VERSION = do { my @v = '$Revision$' =~ /\d+/g;
30                 shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
31
32 =head1 NAME
33
34 C4::Context - Maintain and manipulate the context of a Koha script
35
36 =head1 SYNOPSIS
37
38   use C4::Context;
39
40   use C4::Context("/path/to/koha.conf");
41
42   $config_value = C4::Context->config("config_variable");
43   $db_handle = C4::Context->dbh;
44   $stopwordhash = C4::Context->stopwords;
45
46 =head1 DESCRIPTION
47
48 When a Koha script runs, it makes use of a certain number of things:
49 configuration settings in F</etc/koha.conf>, a connection to the Koha
50 database, and so forth. These things make up the I<context> in which
51 the script runs.
52
53 This module takes care of setting up the context for a script:
54 figuring out which configuration file to load, and loading it, opening
55 a connection to the right database, and so forth.
56
57 Most scripts will only use one context. They can simply have
58
59   use C4::Context;
60
61 at the top.
62
63 Other scripts may need to use several contexts. For instance, if a
64 library has two databases, one for a certain collection, and the other
65 for everything else, it might be necessary for a script to use two
66 different contexts to search both databases. Such scripts should use
67 the C<&set_context> and C<&restore_context> functions, below.
68
69 By default, C4::Context reads the configuration from
70 F</etc/koha.conf>. This may be overridden by setting the C<$KOHA_CONF>
71 environment variable to the pathname of a configuration file to use.
72
73 =head1 METHODS
74
75 =over 2
76
77 =cut
78
79 #'
80 # In addition to what is said in the POD above, a Context object is a
81 # reference-to-hash with the following fields:
82 #
83 # config
84 #       A reference-to-hash whose keys and values are the
85 #       configuration variables and values specified in the config
86 #       file (/etc/koha.conf).
87 # dbh
88 #       A handle to the appropriate database for this context.
89 # dbh_stack
90 #       Used by &set_dbh and &restore_dbh to hold other database
91 #       handles for this context.
92 # Zconn
93 #       A connection object for the Zebra server
94
95 use constant CONFIG_FNAME => "/etc/koha.conf";
96                                 # Default config file, if none is specified
97
98 $context = undef;               # Initially, no context is set
99 @context_stack = ();            # Initially, no saved contexts
100
101 # read_config_file
102 # Reads the specified Koha config file. Returns a reference-to-hash
103 # whose keys are the configuration variables, and whose values are the
104 # configuration values (duh).
105 # Returns undef in case of error.
106 #
107 # Revision History:
108 # 2004-08-10 A. Tarallo: Added code that checks if a variable is already
109 # assigned and prints a message, otherwise create a new entry in the hash to
110 # be returned. 
111 # Also added code that complaints if finds a line that isn't a variable 
112 # assignmet and skips the line.
113 # Added a quick hack that makes the translation between the db_schema
114 # and the DBI driver for that schema.
115 #
116 sub read_config_file
117 {
118         my $fname = shift;      # Config file to read
119         my $retval = {};        # Return value: ref-to-hash holding the
120                                 # configuration
121
122         open (CONF, $fname) or return undef;
123
124         while (<CONF>)
125         {
126                 my $var;                # Variable name
127                 my $value;              # Variable value
128
129                 chomp;
130                 s/#.*//;                # Strip comments
131                 next if /^\s*$/;        # Ignore blank lines
132
133                 # Look for a line of the form
134                 #       var = value
135                 if (!/^\s*(\w+)\s*=\s*(.*?)\s*$/)
136                 {
137                         print STDERR 
138                                 "$_ isn't a variable assignment, skipping it";
139                         next;
140                 }
141
142                 # Found a variable assignment
143                 if ( exists $retval->{$1} )
144                 {
145                         print STDERR "$var was already defined, ignoring\n";
146                 }else{
147                 # Quick hack for allowing databases name in full text
148                         if ( $1 eq "db_scheme" )
149                         {
150                                 $value = db_scheme2dbi($2);
151                         }else {
152                                 $value = $2;
153                         }
154                         $retval->{$1} = $value;
155                 }
156         }
157         close CONF;
158
159         return $retval;
160 }
161
162 # db_scheme2dbi
163 # Translates the full text name of a database into de appropiate dbi name
164
165 sub db_scheme2dbi
166 {
167         my $name = shift;
168
169         for ($name) {
170 # FIXME - Should have other databases. 
171                 if (/mysql/i) { return("mysql"); }
172                 if (/Postgres|Pg|PostgresSQL/) { return("Pg"); }
173                 if (/oracle/i) { return("Oracle"); }
174         }
175         return undef;           # Just in case
176 }
177
178 sub import
179 {
180         my $package = shift;
181         my $conf_fname = shift;         # Config file name
182         my $context;
183
184         # Create a new context from the given config file name, if
185         # any, then set it as the current context.
186         $context = new C4::Context($conf_fname);
187         return undef if !defined($context);
188         $context->set_context;
189 }
190
191 =item new
192
193   $context = new C4::Context;
194   $context = new C4::Context("/path/to/koha.conf");
195
196 Allocates a new context. Initializes the context from the specified
197 file, which defaults to either the file given by the C<$KOHA_CONF>
198 environment variable, or F</etc/koha.conf>.
199
200 C<&new> does not set this context as the new default context; for
201 that, use C<&set_context>.
202
203 =cut
204
205 #'
206 # Revision History:
207 # 2004-08-10 A. Tarallo: Added check if the conf file is not empty
208 sub new
209 {
210         my $class = shift;
211         my $conf_fname = shift;         # Config file to load
212         my $self = {};
213
214         # check that the specified config file exists and is not empty
215         undef $conf_fname unless 
216             (defined $conf_fname && -e $conf_fname && -s $conf_fname);
217         # Figure out a good config file to load if none was specified.
218         if (!defined($conf_fname))
219         {
220                 # If the $KOHA_CONF environment variable is set, use
221                 # that. Otherwise, use the built-in default.
222                 $conf_fname = $ENV{"KOHA_CONF"} || CONFIG_FNAME;
223         }
224         $self->{"config_file"} = $conf_fname;
225
226         # Load the desired config file.
227         $self->{"config"} = &read_config_file($conf_fname);
228         warn "read_config_file($conf_fname) returned undef" if !defined($self->{"config"});
229         return undef if !defined($self->{"config"});
230
231         $self->{"dbh"} = undef;         # Database handle
232         $self->{"Zconn"} = undef;       # Zebra Connection
233         $self->{"stopwords"} = undef; # stopwords list
234         $self->{"marcfromkohafield"} = undef; # the hash with relations between koha table fields and MARC field/subfield
235         $self->{"userenv"} = undef;             # User env
236         $self->{"activeuser"} = undef;          # current active user
237
238         bless $self, $class;
239         return $self;
240 }
241
242 =item set_context
243
244   $context = new C4::Context;
245   $context->set_context();
246 or
247   set_context C4::Context $context;
248
249   ...
250   restore_context C4::Context;
251
252 In some cases, it might be necessary for a script to use multiple
253 contexts. C<&set_context> saves the current context on a stack, then
254 sets the context to C<$context>, which will be used in future
255 operations. To restore the previous context, use C<&restore_context>.
256
257 =cut
258
259 #'
260 sub set_context
261 {
262         my $self = shift;
263         my $new_context;        # The context to set
264
265         # Figure out whether this is a class or instance method call.
266         #
267         # We're going to make the assumption that control got here
268         # through valid means, i.e., that the caller used an instance
269         # or class method call, and that control got here through the
270         # usual inheritance mechanisms. The caller can, of course,
271         # break this assumption by playing silly buggers, but that's
272         # harder to do than doing it properly, and harder to check
273         # for.
274         if (ref($self) eq "")
275         {
276                 # Class method. The new context is the next argument.
277                 $new_context = shift;
278         } else {
279                 # Instance method. The new context is $self.
280                 $new_context = $self;
281         }
282
283         # Save the old context, if any, on the stack
284         push @context_stack, $context if defined($context);
285
286         # Set the new context
287         $context = $new_context;
288 }
289
290 =item restore_context
291
292   &restore_context;
293
294 Restores the context set by C<&set_context>.
295
296 =cut
297
298 #'
299 sub restore_context
300 {
301         my $self = shift;
302
303         if ($#context_stack < 0)
304         {
305                 # Stack underflow.
306                 die "Context stack underflow";
307         }
308
309         # Pop the old context and set it.
310         $context = pop @context_stack;
311
312         # FIXME - Should this return something, like maybe the context
313         # that was current when this was called?
314 }
315
316 =item config
317
318   $value = C4::Context->config("config_variable");
319
320   $value = C4::Context->config_variable;
321
322 Returns the value of a variable specified in the configuration file
323 from which the current context was created.
324
325 The second form is more compact, but of course may conflict with
326 method names. If there is a configuration variable called "new", then
327 C<C4::Config-E<gt>new> will not return it.
328
329 =cut
330
331 #'
332 sub config
333 {
334         my $self = shift;
335         my $var = shift;                # The config variable to return
336
337         return undef if !defined($context->{"config"});
338                         # Presumably $self->{config} might be
339                         # undefined if the config file given to &new
340                         # didn't exist, and the caller didn't bother
341                         # to check the return value.
342
343         # Return the value of the requested config variable
344         return $context->{"config"}{$var};
345 }
346
347 =item preference
348
349   $sys_preference = C4::Context->preference("some_variable");
350
351 Looks up the value of the given system preference in the
352 systempreferences table of the Koha database, and returns it. If the
353 variable is not set, or in case of error, returns the undefined value.
354
355 =cut
356
357 #'
358 # FIXME - The preferences aren't likely to change over the lifetime of
359 # the script (and things might break if they did change), so perhaps
360 # this function should cache the results it finds.
361 sub preference
362 {
363         my $self = shift;
364         my $var = shift;                # The system preference to return
365         my $retval;                     # Return value
366         my $dbh = C4::Context->dbh;     # Database handle
367         my $sth;                        # Database query handle
368
369         # Look up systempreferences.variable==$var
370         $retval = $dbh->selectrow_array(<<EOT);
371                 SELECT  value
372                 FROM    systempreferences
373                 WHERE   variable='$var'
374                 LIMIT   1
375 EOT
376         return $retval;
377 }
378
379 sub boolean_preference ($) {
380         my $self = shift;
381         my $var = shift;                # The system preference to return
382         my $it = preference($self, $var);
383         return defined($it)? C4::Boolean::true_p($it): undef;
384 }
385
386 # AUTOLOAD
387 # This implements C4::Config->foo, and simply returns
388 # C4::Context->config("foo"), as described in the documentation for
389 # &config, above.
390
391 # FIXME - Perhaps this should be extended to check &config first, and
392 # then &preference if that fails. OTOH, AUTOLOAD could lead to crappy
393 # code, so it'd probably be best to delete it altogether so as not to
394 # encourage people to use it.
395 sub AUTOLOAD
396 {
397         my $self = shift;
398
399         $AUTOLOAD =~ s/.*:://;          # Chop off the package name,
400                                         # leaving only the function name.
401         return $self->config($AUTOLOAD);
402 }
403
404 =item Zconn
405
406 $Zconn = C4::Context->Zconn
407
408 Returns a connection to the Zebra database for the current
409 context. If no connection has yet been made, this method 
410 creates one and connects.
411
412 =cut
413
414 sub Zconn {
415         my $self = shift;
416         my $rs;
417         my $Zconn;
418         if (defined($context->{"Zconn"})) {
419             $Zconn = $context->{"Zconn"};
420 #           $rs=$Zconn->search_pqf('@attr 1=4 mineral');
421 #           if ($Zconn->errcode() != 0) {
422 #               $context->{"Zconn"} = &new_Zconn();
423 #               return $context->{"Zconn"};
424 #           }
425             return $context->{"Zconn"};
426         } else { 
427                 $context->{"Zconn"} = &new_Zconn();
428                 return $context->{"Zconn"};
429         }
430 }
431
432 =item new_Zconn
433
434 Internal helper function. creates a new database connection from
435 the data given in the current context and returns it.
436
437 =cut
438
439 sub new_Zconn {
440         use ZOOM;
441         my $Zconn;
442         eval {
443                 $Zconn = new ZOOM::Connection(C4::Context->config("zebradb"));
444         };
445         if ($@){
446                 warn "Error ", $@->code(), ": ", $@->message(), "\n";
447                 die "Fatal error, cant connect to z3950 server";
448         }
449         $Zconn->option(cqlfile => C4::Context->config("intranetdir")."/zebra/pqf.properties");
450         $Zconn->option(preferredRecordSyntax => "xml");
451         return $Zconn;
452 }
453
454 # _new_dbh
455 # Internal helper function (not a method!). This creates a new
456 # database connection from the data given in the current context, and
457 # returns it.
458 sub _new_dbh
459 {
460         my $db_driver = $context->{"config"}{"db_scheme"} || "mysql";
461         my $db_name   = $context->{"config"}{"database"};
462         my $db_host   = $context->{"config"}{"hostname"};
463         my $db_user   = $context->{"config"}{"user"};
464         my $db_passwd = $context->{"config"}{"pass"};
465         my $dbh= DBI->connect("DBI:$db_driver:$db_name:$db_host",
466                             $db_user, $db_passwd);
467         # Koha 3.0 is utf-8, so force utf8 communication between mySQL and koha, whatever the mysql default config.
468         # this is better than modifying my.cnf (and forcing all communications to be in utf8)
469         $dbh->do("set NAMES 'utf8'");
470         return $dbh;
471 }
472
473 =item dbh
474
475   $dbh = C4::Context->dbh;
476
477 Returns a database handle connected to the Koha database for the
478 current context. If no connection has yet been made, this method
479 creates one, and connects to the database.
480
481 This database handle is cached for future use: if you call
482 C<C4::Context-E<gt>dbh> twice, you will get the same handle both
483 times. If you need a second database handle, use C<&new_dbh> and
484 possibly C<&set_dbh>.
485
486 =cut
487
488 #'
489 sub dbh
490 {
491         my $self = shift;
492         my $sth;
493
494         if (defined($context->{"dbh"})) {
495             $sth=$context->{"dbh"}->prepare("select 1");
496             return $context->{"dbh"} if (defined($sth->execute));
497         }
498
499         # No database handle or it died . Create one.
500         $context->{"dbh"} = &_new_dbh();
501
502         return $context->{"dbh"};
503 }
504
505 =item new_dbh
506
507   $dbh = C4::Context->new_dbh;
508
509 Creates a new connection to the Koha database for the current context,
510 and returns the database handle (a C<DBI::db> object).
511
512 The handle is not saved anywhere: this method is strictly a
513 convenience function; the point is that it knows which database to
514 connect to so that the caller doesn't have to know.
515
516 =cut
517
518 #'
519 sub new_dbh
520 {
521         my $self = shift;
522
523         return &_new_dbh();
524 }
525
526 =item set_dbh
527
528   $my_dbh = C4::Connect->new_dbh;
529   C4::Connect->set_dbh($my_dbh);
530   ...
531   C4::Connect->restore_dbh;
532
533 C<&set_dbh> and C<&restore_dbh> work in a manner analogous to
534 C<&set_context> and C<&restore_context>.
535
536 C<&set_dbh> saves the current database handle on a stack, then sets
537 the current database handle to C<$my_dbh>.
538
539 C<$my_dbh> is assumed to be a good database handle.
540
541 =cut
542
543 #'
544 sub set_dbh
545 {
546         my $self = shift;
547         my $new_dbh = shift;
548
549         # Save the current database handle on the handle stack.
550         # We assume that $new_dbh is all good: if the caller wants to
551         # screw himself by passing an invalid handle, that's fine by
552         # us.
553         push @{$context->{"dbh_stack"}}, $context->{"dbh"};
554         $context->{"dbh"} = $new_dbh;
555 }
556
557 =item restore_dbh
558
559   C4::Context->restore_dbh;
560
561 Restores the database handle saved by an earlier call to
562 C<C4::Context-E<gt>set_dbh>.
563
564 =cut
565
566 #'
567 sub restore_dbh
568 {
569         my $self = shift;
570
571         if ($#{$context->{"dbh_stack"}} < 0)
572         {
573                 # Stack underflow
574                 die "DBH stack underflow";
575         }
576
577         # Pop the old database handle and set it.
578         $context->{"dbh"} = pop @{$context->{"dbh_stack"}};
579
580         # FIXME - If it is determined that restore_context should
581         # return something, then this function should, too.
582 }
583
584 =item marcfromkohafield
585
586   $dbh = C4::Context->marcfromkohafield;
587
588 Returns a hash with marcfromkohafield.
589
590 This hash is cached for future use: if you call
591 C<C4::Context-E<gt>marcfromkohafield> twice, you will get the same hash without real DB access
592
593 =cut
594
595 #'
596 sub marcfromkohafield
597 {
598         my $retval = {};
599
600         # If the hash already exists, return it.
601         return $context->{"marcfromkohafield"} if defined($context->{"marcfromkohafield"});
602
603         # No hash. Create one.
604         $context->{"marcfromkohafield"} = &_new_marcfromkohafield();
605
606         return $context->{"marcfromkohafield"};
607 }
608
609 # _new_marcfromkohafield
610 # Internal helper function (not a method!). This creates a new
611 # hash with stopwords
612 sub _new_marcfromkohafield
613 {
614         my $dbh = C4::Context->dbh;
615         my $marcfromkohafield;
616         my $sth = $dbh->prepare("select frameworkcode,kohafield,tagfield,tagsubfield from marc_subfield_structure where kohafield > ''");
617         $sth->execute;
618         while (my ($frameworkcode,$kohafield,$tagfield,$tagsubfield) = $sth->fetchrow) {
619                 my $retval = {};
620                 $marcfromkohafield->{$frameworkcode}->{$kohafield} = [$tagfield,$tagsubfield];
621         }
622         return $marcfromkohafield;
623 }
624
625 =item stopwords
626
627   $dbh = C4::Context->stopwords;
628
629 Returns a hash with stopwords.
630
631 This hash is cached for future use: if you call
632 C<C4::Context-E<gt>stopwords> twice, you will get the same hash without real DB access
633
634 =cut
635
636 #'
637 sub stopwords
638 {
639         my $retval = {};
640
641         # If the hash already exists, return it.
642         return $context->{"stopwords"} if defined($context->{"stopwords"});
643
644         # No hash. Create one.
645         $context->{"stopwords"} = &_new_stopwords();
646
647         return $context->{"stopwords"};
648 }
649
650 # _new_stopwords
651 # Internal helper function (not a method!). This creates a new
652 # hash with stopwords
653 sub _new_stopwords
654 {
655         my $dbh = C4::Context->dbh;
656         my $stopwordlist;
657         my $sth = $dbh->prepare("select word from stopwords");
658         $sth->execute;
659         while (my $stopword = $sth->fetchrow_array) {
660                 my $retval = {};
661                 $stopwordlist->{$stopword} = uc($stopword);
662         }
663         $stopwordlist->{A} = "A" unless $stopwordlist;
664         return $stopwordlist;
665 }
666
667 =item userenv
668
669   C4::Context->userenv;
670
671 Builds a hash for user environment variables.
672
673 This hash shall be cached for future use: if you call
674 C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
675
676 set_userenv is called in Auth.pm
677
678 =cut
679
680 #'
681 sub userenv
682 {
683         my $var = $context->{"activeuser"};
684         return $context->{"userenv"}->{$var} if (defined $context->{"userenv"}->{$var});
685         return 0;
686         warn "NO CONTEXT for $var";
687 }
688
689 =item set_userenv
690
691   C4::Context->set_userenv($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $userflags, $emailaddress);
692
693 Informs a hash for user environment variables.
694
695 This hash shall be cached for future use: if you call
696 C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
697
698 set_userenv is called in Auth.pm
699
700 =cut
701 #'
702 sub set_userenv{
703         my ($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $userflags, $emailaddress)= @_;
704         my $var=$context->{"activeuser"};
705         my $cell = {
706                 "number"     => $usernum,
707                 "id"         => $userid,
708                 "cardnumber" => $usercnum,
709 #               "firstname"  => $userfirstname,
710 #               "surname"    => $usersurname,
711 #possibly a law problem
712                 "branch"     => $userbranch,
713                 "flags"      => $userflags,
714                 "emailaddress"  => $emailaddress,
715         };
716         $context->{userenv}->{$var} = $cell;
717         return $cell;
718 }
719
720 =item _new_userenv
721
722   C4::Context->_new_userenv($session);
723
724 Builds a hash for user environment variables.
725
726 This hash shall be cached for future use: if you call
727 C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
728
729 _new_userenv is called in Auth.pm
730
731 =cut
732
733 #'
734 sub _new_userenv
735 {
736         shift;
737         my ($sessionID)= @_;
738         $context->{"activeuser"}=$sessionID;
739 }
740
741 =item _unset_userenv
742
743   C4::Context->_unset_userenv;
744
745 Destroys the hash for activeuser user environment variables.
746
747 =cut
748 #'
749
750 sub _unset_userenv
751 {
752         my ($sessionID)= @_;
753         undef $context->{"activeuser"} if ($context->{"activeuser"} eq $sessionID);
754 }
755
756
757
758 1;
759 __END__
760
761 =back
762
763 =head1 ENVIRONMENT
764
765 =over 4
766
767 =item C<KOHA_CONF>
768
769 Specifies the configuration file to read.
770
771 =back
772
773 =head1 SEE ALSO
774
775 DBI(3)
776
777 =head1 AUTHOR
778
779 Andrew Arensburger <arensb at ooblick dot com>
780
781 =cut
782 # $Log$
783 # Revision 1.33  2006/03/15 11:21:56  plg
784 # bug fixed: utf-8 data where not displayed correctly in screens. Supposing
785 # your data are truely utf-8 encoded in your database, they should be
786 # correctly displayed. "set names 'UTF8'" on mysql connection (C4/Context.pm)
787 # is mandatory and "binmode" to utf8 (C4/Interface/CGI/Output.pm) seemed to
788 # converted data twice, so it was removed.
789 #
790 # Revision 1.32  2006/03/03 17:25:01  hdl
791 # Bug fixing : a line missed a comment sign.
792 #
793 # Revision 1.31  2006/03/03 16:45:36  kados
794 # Remove the search that tests the Zconn -- warning, still no fault
795 # tollerance
796 #
797 # Revision 1.30  2006/02/22 00:56:59  kados
798 # First go at a connection object for Zebra. You can now get a
799 # connection object by doing:
800 #
801 # my $Zconn = C4::Context->Zconn;
802 #
803 # My initial tests indicate that as soon as your funcion ends
804 # (ie, when you're done doing something) the connection will be
805 # closed automatically. There may be some other way to make the
806 # connection more stateful, I'm not sure...
807 #
808 # Local Variables:
809 # tab-width: 4
810 # End: