Fixed some run-time bugs, so it'll actually load.
[koha_fer] / 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 package C4::Context;
19 use strict;
20 use DBI;
21
22 use vars qw($VERSION $AUTOLOAD),
23         qw($context),
24         qw(@context_stack);
25
26 $VERSION = do { my @v = '$Revision$' =~ /\d+/g;
27                 shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
28
29 =head1 NAME
30
31 C4::Context - Maintain and manipulate the context of a Koha script
32
33 =head1 SYNOPSIS
34
35   use C4::Context;
36
37   use C4::Context("/path/to/koha.conf");
38
39   $config_value = C4::Context->config("config_variable");
40   $db_handle = C4::Context->dbh;
41
42 =head1 DESCRIPTION
43
44 When a Koha script runs, it makes use of a certain number of things:
45 configuration settings in F</etc/koha.conf>, a connection to the Koha
46 database, and so forth. These things make up the I<context> in which
47 the script runs.
48
49 This module takes care of setting up the context for a script:
50 figuring out which configuration file to load, and loading it, opening
51 a connection to the right database, and so forth.
52
53 Most scripts will only use one context. They can simply have
54
55   use C4::Context;
56
57 at the top.
58
59 Other scripts may need to use several contexts. For instance, if a
60 library has two databases, one for a certain collection, and the other
61 for everything else, it might be necessary for a script to use two
62 different contexts to search both databases. Such scripts should use
63 the C<&set_context> and C<&restore_context> functions, below.
64
65 By default, C4::Context reads the configuration from
66 F</etc/koha.conf>. This may be overridden by setting the C<$KOHA_CONF>
67 environment variable to the pathname of a configuration file to use.
68
69 =head1 METHODS
70
71 =over 2
72
73 =cut
74 #'
75 # In addition to what is said in the POD above, a Context object is a
76 # reference-to-hash with the following fields:
77 #
78 # config
79 #       A reference-to-hash whose keys and values are the
80 #       configuration variables and values specified in the config
81 #       file (/etc/koha.conf).
82 # dbh
83 #       A handle to the appropriate database for this context.
84 # dbh_stack
85 #       Used by &set_dbh and &restore_dbh to hold other database
86 #       handles for this context.
87
88 use constant CONFIG_FNAME => "/etc/koha.conf";
89                                 # Default config file, if none is specified
90
91 $context = undef;               # Initially, no context is set
92 @context_stack = ();            # Initially, no saved contexts
93
94 # read_config_file
95 # Reads the specified Koha config file. Returns a reference-to-hash
96 # whose keys are the configuration variables, and whose values are the
97 # configuration values (duh).
98 # Returns undef in case of error.
99 sub read_config_file
100 {
101         my $fname = shift;      # Config file to read
102         my $retval = {};        # Return value: ref-to-hash holding the
103                                 # configuration
104
105         open (CONF, $fname) or return undef;
106
107         while (<CONF>)
108         {
109                 my $var;                # Variable name
110                 my $value;              # Variable value
111
112                 chomp;
113                 s/#.*//;                # Strip comments
114                 next if /^\s*$/;        # Ignore blank lines
115
116                 # Look for a line of the form
117                 #       var = value
118                 if (!/^\s*(\w+)\s*=\s*(.*?)\s*$/)
119                 {
120                         # FIXME - Complain about bogus line
121                         next;
122                 }
123
124                 # Found a variable assignment
125                 # FIXME - Ought to complain is this line sets a
126                 # variable that was already set.
127                 $var = $1;
128                 $value = $2;
129                 $retval->{$var} = $value;
130         }
131         close CONF;
132
133         return $retval;
134 }
135
136 sub import
137 {
138         my $package = shift;
139         my $conf_fname = shift;         # Config file name
140         my $context;
141
142         # Create a new context from the given config file name, if
143         # any, then set it as the current context.
144         $context = new C4::Context($conf_fname);
145         return undef if !defined($context);
146         $context->set_context;
147 }
148
149 =item new
150
151   $context = new C4::Context;
152   $context = new C4::Context("/path/to/koha.conf");
153
154 Allocates a new context. Initializes the context from the specified
155 file, which defaults to either the file given by the C<$KOHA_CONF>
156 environment variable, or F</etc/koha.conf>.
157
158 C<&new> does not set this context as the new default context; for
159 that, use C<&set_context>.
160
161 =cut
162 #'
163 sub new
164 {
165         my $class = shift;
166         my $conf_fname = shift;         # Config file to load
167         my $self = {};
168
169         # Figure out a good config file to load if none was specified.
170         if (!defined($conf_fname))
171         {
172                 # If the $KOHA_CONF environment variable is set, use
173                 # that. Otherwise, use the built-in default.
174                 $conf_fname = $ENV{"KOHA_CONF"} ||
175                                 CONFIG_FNAME;
176         }
177
178         $self->{"config_file"} = $conf_fname;
179
180         # Load the desired config file.
181         $self->{"config"} = &read_config_file($conf_fname);
182         return undef if !defined($self->{"config"});
183
184         $self->{"dbh"} = undef;         # Database handle
185
186         bless $self, $class;
187         return $self;
188 }
189
190 =item set_context
191
192   $context = new C4::Context;
193   $context->set_context();
194 or
195   set_context C4::Context $context;
196
197   ...
198   restore_context C4::Context;
199
200 In some cases, it might be necessary for a script to use multiple
201 contexts. C<&set_context> saves the current context on a stack, then
202 sets the context to C<$context>, which will be used in future
203 operations. To restore the previous context, use C<&restore_context>.
204
205 =cut
206 #'
207 sub set_context
208 {
209         my $self = shift;
210         my $new_context;        # The context to set
211
212         # Figure out whether this is a class or instance method call.
213         #
214         # We're going to make the assumption that control got here
215         # through valid means, i.e., that the caller used an instance
216         # or class method call, and that control got here through the
217         # usual inheritance mechanisms. The caller can, of course,
218         # break this assumption by playing silly buggers, but that's
219         # harder to do than doing it properly, and harder to check
220         # for.
221         if (ref($self) eq "")
222         {
223                 # Class method. The new context is the next argument.
224                 $new_context = shift;
225         } else {
226                 # Instance method. The new context is $self.
227                 $new_context = $self;
228         }
229
230         # Save the old context, if any, on the stack
231         push @context_stack, $context if defined($context);
232
233         # Set the new context
234         $context = $new_context;
235 }
236
237 =item restore_context
238
239   &restore_context;
240
241 Restores the context set by C<&set_context>.
242
243 =cut
244 #'
245 sub restore_context
246 {
247         my $self = shift;
248
249         if ($#context_stack < 0)
250         {
251                 # Stack underflow.
252                 die "Context stack underflow";
253         }
254
255         # Pop the old context and set it.
256         $context = pop @context_stack;
257
258         # FIXME - Should this return something, like maybe the context
259         # that was current when this was called?
260 }
261
262 =item config
263
264   $value = C4::Context->config("config_variable");
265
266   $value = C4::Context->config_variable;
267
268 Returns the value of a variable specified in the configuration file
269 from which the current context was created.
270
271 The second form is more compact, but of course may conflict with
272 method names. If there is a configuration variable called "new", then
273 C<C4::Config-E<gt>new> will not return it.
274
275 =cut
276 #'
277 sub config
278 {
279         my $self = shift;
280         my $var = shift;                # The config variable to return
281
282         return undef if !defined($context->{"config"});
283                         # Presumably $self->{config} might be
284                         # undefined if the config file given to &new
285                         # didn't exist, and the caller didn't bother
286                         # to check the return value.
287
288         # Return the value of the requested config variable
289         return $context->{"config"}{$var};
290 }
291
292 # AUTOLOAD
293 # This implements C4::Config->foo, and simply returns
294 # C4::Context->config("foo"), as described in the documentation for
295 # &config, above.
296 sub AUTOLOAD
297 {
298         my $self = shift;
299
300         $AUTOLOAD =~ s/.*:://;          # Chop off the package name,
301                                         # leaving only the function name.
302         return $self->config($AUTOLOAD);
303 }
304
305 # _new_dbh
306 # Internal helper function (not a method!). This creates a new
307 # database connection from the data given in the current context, and
308 # returns it.
309 sub _new_dbh
310 {
311         my $db_driver = $context->{"config"}{"db_scheme"} || "mysql";
312         my $db_name   = $context->{"config"}{"database"};
313         my $db_host   = $context->{"config"}{"hostname"};
314         my $db_user   = $context->{"config"}{"user"};
315         my $db_passwd = $context->{"config"}{"pass"};
316
317         return DBI->connect("DBI:$db_driver:$db_name:$db_host",
318                             $db_user, $db_passwd);
319 }
320
321 =item dbh
322
323   $dbh = C4::Context->dbh;
324
325 Returns a database handle connected to the Koha database for the
326 current context. If no connection has yet been made, this method
327 creates one, and connects to the database.
328
329 This database handle is cached for future use: if you call
330 C<C4::Context-E<gt>dbh> twice, you will get the same handle both
331 times. If you need a second database handle, use C<&new_dbh> and
332 possibly C<&set_dbh>.
333
334 =cut
335 #'
336 sub dbh
337 {
338         my $self = shift;
339
340         # If there's already a database handle, return it.
341         return $context->{"dbh"} if defined($context->{"dbh"});
342
343         # No database handle yet. Create one.
344         $context->{"dbh"} = &_new_dbh();
345
346         return $context->{"dbh"};
347 }
348
349 =item new_dbh
350
351   $dbh = C4::Context->new_dbh;
352
353 Creates a new connection to the Koha database for the current context,
354 and returns the database handle (a C<DBI::db> object).
355
356 The handle is not saved anywhere: this method is strictly a
357 convenience function; the point is that it knows which database to
358 connect to so that the caller doesn't have to know.
359
360 =cut
361 #'
362 sub new_dbh
363 {
364         my $self = shift;
365
366         return &_new_dbh();
367 }
368
369 =item set_dbh
370
371   $my_dbh = C4::Connect->new_dbh;
372   C4::Connect->set_dbh($my_dbh);
373   ...
374   C4::Connect->restore_dbh;
375
376 C<&set_dbh> and C<&restore_dbh> work in a manner analogous to
377 C<&set_context> and C<&restore_context>.
378
379 C<&set_dbh> saves the current database handle on a stack, then sets
380 the current database handle to C<$my_dbh>.
381
382 C<$my_dbh> is assumed to be a good database handle.
383
384 =cut
385 #'
386 sub set_dbh
387 {
388         my $self = shift;
389         my $new_dbh = shift;
390
391         # Save the current database handle on the handle stack.
392         # We assume that $new_dbh is all good: if the caller wants to
393         # screw himself by passing an invalid handle, that's fine by
394         # us.
395         push @{$context->{"dbh_stack"}}, $context->{"dbh"};
396         $context->{"dbh"} = $new_dbh;
397 }
398
399 =item restore_dbh
400
401   C4::Context->restore_dbh;
402
403 Restores the database handle saved by an earlier call to
404 C<C4::Context-E<gt>set_dbh>.
405
406 =cut
407 #'
408 sub restore_dbh
409 {
410         my $self = shift;
411
412         if ($#{$context->{"dbh_stack"}} < 0)
413         {
414                 # Stack underflow
415                 die "DBH stack underflow";
416         }
417
418         # Pop the old database handle and set it.
419         $context->{"dbh"} = pop @{$context->{"dbh_stack"}};
420
421         # FIXME - If it is determined that restore_context should
422         # return something, then this function should, too.
423 }
424
425 1;
426 __END__
427 =back
428
429 =head1 ENVIRONMENT
430
431 =over 4
432
433 =item C<KOHA_CONF>
434
435 Specifies the configuration file to read.
436
437 =back
438
439 =head1 SEE ALSO
440
441 L<DBI(3)|DBI>
442
443 =head1 AUTHOR
444
445 Andrew Arensburger
446
447 =cut