Let's say we have an object we want to be able to access anywhere in the code, without making it a global variable or passing it as an argument to functions. The singleton design pattern helps here. Rather than implementing this pattern from scratch, we will use Class::Singleton.
For example, if we have a class Book::DBIHandle that returns an instance of the opened database connection handle, we can use it in the TransHandler phase's handler (see Example A-6).
package Book::TransHandler;
use Book::DBIHandle;
use Apache::Constants qw(:common);
sub handler {
my $r = shift;
my $dbh = Book::DBIHandle->instance->dbh;
$dbh->do("show tables");
# ...
return OK;
}
1;
We can then use the same database handle in the content-generation phase (see Example A-7).
package Book::ContentHandler;
use Book::DBIHandle;
use Apache::Constants qw(:common);
sub handler {
my $r = shift;
my $dbh = Book::DBIHandle->instance->dbh;
$dbh->do("select from foo...");
# ...
return OK;
}
1;
In httpd.conf, use the following setup for the TransHandler and content-generation phases:
PerlTransHandler +Book::TransHandler
<Location /dbihandle>
SetHandler perl-script
PerlHandler +Book::ContentHandler
</Location>
This specifies that Book::TransHandlershould be used as the PerlTransHandler, and Book::ContentHandlershould be used as a content-generation handler. We use the + prefix to preload both modules at server startup, in order to improve memory sharing between the processes (as explained in Chapter 10).
Book::DBIHandle, shown in Example A-8, is a simple subclass of Class::Singleton that is used by both handlers.
package Book::DBIHandle;
use strict;
use warnings;
use DBI;
use Class::Singleton;
@Book::DBIHandle::ISA = qw(Class::Singleton);
sub _new_instance {
my($class, $args) = @_;
my $self = DBI->connect($args->{dsn}, $args->{user},
$args->{passwd}, $args->{options})
or die "Cannot connect to database: $DBI::errstr";
return bless $self, $class;
}
sub dbh {
my $self = shift;
return $$self;
}
1;
Book::DBIHandle inherits the instance( ) method from Class::Singleton and overrides its _new_instance( ) method. _new_instance( ) accepts the connect( ) arguments and opens the connection using these arguments. The _new_instance( ) method will be called only the first time the instance( ) method is called.
We have used a reference to a scalar ($dbh) for the Book::DBIHandle objects. Therefore, we need to dereference the objects when we want to access the database handle in the code. The dbh( ) method does this for us.
Since each child process must have a unique database connection, we initialize the database handle during the PerlChildInit phase, similar to DBI::connect_on_init( ). See Example A-9.
package Book::ChildInitHandler;
use strict;
use Book::DBIHandle;
use Apache;
sub handler {
my $s = Apache->server;
my $dbh = Book::DBIHandle->instance(
{ dsn => $s->dir_config('DATABASE_DSN'),
user => $s->dir_config('DATABASE_USER'),
passwd => $s->dir_config('DATABASE_PASSWD'),
options => {
AutoCommit => 0,
RaiseError => 1,
PrintError => 0,
ChopBlanks => 1,
},
}
);
$s->log_error("$$: Book::DBIHandle object allocated, handle=$dbh");
}
1;
Here, the instance( ) method is called for the first time, so its arguments are passed to the new _new_instance( ) method. _new_instance( ) initializes the database connection.
httpd.conf needs to be adjusted to enable the new ChildInitHandler:
PerlSetVar DATABASE_DSN "DBI:mysql:test::localhost" PerlSetVar DATABASE_USER "foo" PerlSetVar DATABASE_PASSWD "bar" PerlChildInitHandler +Book::ChildInitHandler
Copyright © 2003 O'Reilly & Associates. All rights reserved.