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