File Coverage

blib/lib/DBR.pm
Criterion Covered Total %
statement 65 97 67.0
branch 13 40 32.5
condition 3 30 10.0
subroutine 17 23 73.9
pod 4 9 44.4
total 102 199 51.2


line stmt bran cond sub pod time code
1             # the contents of this file are Copyright (c) 2004-2009 Daniel Norman
2             # This program is free software; you can redistribute it and/or
3             # modify it under the terms of the GNU General Public License as
4             # published by the Free Software Foundation.
5              
6             package DBR;
7              
8 18     18   809970 use strict;
  18         47  
  18         1119  
9 18     18   8352 use DBR::Handle;
  18         68  
  18         626  
10 18     18   11181 use DBR::Config;
  18         78  
  18         666  
11 18     18   134 use DBR::Config::Instance;
  18         41  
  18         360  
12 18     18   12497 use DBR::Misc::Session;
  18         70  
  18         876  
13 18     18   155 use Scalar::Util 'blessed';
  18         47  
  18         1041  
14 18     18   116 use base 'DBR::Common';
  18         42  
  18         2329  
15 18     18   11500 use DBR::Util::Logger;
  18         67  
  18         1304  
16 18     18   210 use Carp;
  18         47  
  18         6352  
17              
18             our $VERSION = '1.5';
19              
20             my %APP_BY_CONF;
21             my %CONF_BY_APP;
22             my %OBJECTS;
23             my $CT;
24              
25             sub import {
26 37     37   3187 my $pkg = shift;
27 37         115 my %params = @_;
28              
29 37         167 my ($callpack, $callfile, $callline) = caller;
30              
31 37         103 my $app = $params{app};
32 37 50 0     170 my $exc = exists $params{use_exceptions} ? $params{use_exceptions} || 0 : 1;
33 37         73 my $conf;
34              
35 37 50 33     309 if( $params{conf} ){
    50          
36 0 0       0 croak "conf file '$params{conf}' not found" unless -e $params{conf};
37              
38 0         0 $conf = $params{conf};
39 0   0     0 $app ||= $APP_BY_CONF{ $conf } ||= 'auto_' . $CT++; # use existing app id if conf exists, or make one up
      0        
40 0         0 $CONF_BY_APP{ $app } = $conf;
41             }elsif ( defined $app && length $app ){
42 0         0 $conf = $CONF_BY_APP{ $app };
43             }
44              
45 37 50       1054 return 1 unless $app; # No import requested
46              
47 0 0       0 if($conf){
48 0   0     0 $OBJECTS{ $app }{ $exc } ||= DBR->new(
      0        
      0        
49             -logger => DBR::Util::Logger->new(
50             -logpath => $params{logpath} || '/tmp/dbr_auto.log',
51             -logLevel => $params{loglevel} || 'warn'
52             ),
53             -conf => $conf,
54             -use_exceptions => $exc,
55             );
56             }
57              
58 0 0       0 my $dbr = $OBJECTS{ $app }{ $exc } or croak "No DBR object could be located";
59              
60 18     18   132 no strict 'refs';
  18         65  
  18         22554  
61 0         0 *{"${callpack}::dbr_connect"} =
62             sub {
63 0 0 0 0   0 shift if blessed($_[0]) || $_[0]->isa( [caller]->[0] );
64 0         0 $dbr->connect(@_);
65 0         0 };
66            
67 0         0 *{"${callpack}::dbr_instance"} =
68             sub {
69 0 0 0 0   0 shift if blessed($_[0]) || $_[0]->isa( [caller]->[0] );
70 0         0 $dbr->get_instance(@_);
71 0         0 };
72            
73              
74             }
75             sub new {
76 17     17 1 128 my( $package ) = shift;
77 17         883 my %params = @_;
78 17         95 my $self = {logger => $params{-logger}};
79              
80 17         54 bless( $self, $package );
81              
82 17 50       92 return $self->_error("Error: -conf must be specified") unless $params{-conf};
83              
84 17 50       444 return $self->_error("Failed to create DBR::Util::Session object") unless
    50          
85             $self->{session} = DBR::Misc::Session->new(
86             logger => $self->{logger},
87             admin => $params{-admin} ? 1 : 0, # make the user jump through some hoops for updating metadata
88             fudge_tz => $params{-fudge_tz},
89             use_exceptions => $params{-use_exceptions},
90             );
91              
92 17 50       374 return $self->_error("Failed to create DBR::Config object") unless
93             my $config = DBR::Config->new( session => $self->{session} );
94              
95 17 50       157 $config -> load_file(
96             dbr => $self,
97             file => $params{-conf}
98             ) or return $self->_error("Failed to load DBR conf file");
99              
100              
101 17         136 DBR::Config::Instance->flush_all_handles(); # Make it safer for forking
102              
103 17         1682 return( $self );
104             }
105              
106              
107             sub setlogger {
108 0     0 0 0 my $self = shift;
109 0         0 $self->{logger} = shift;
110             }
111              
112 35     35 0 1463 sub session { $_[0]->{session} }
113              
114             sub connect {
115 15     15 1 27522 my $self = shift;
116 15         46 my $name = shift;
117 15         35 my $class = shift;
118 15         35 my $flag;
119              
120 15 50 33     109 if ($class && $class eq 'dbh') { # legacy
121 0         0 $flag = 'dbh';
122 0         0 $class = undef;
123             }
124              
125 15 50       167 my $instance = DBR::Config::Instance->lookup(
126             dbr => $self,
127             session => $self->{session},
128             handle => $name,
129             class => $class
130             ) or return $self->_error("No config found for db '$name' class '$class'");
131              
132 15         89 return $instance->connect($flag);
133              
134             }
135              
136             sub get_instance {
137 35     35 1 234 my $self = shift;
138 35         2481 my $name = shift;
139 35         72 my $class = shift;
140 35         64 my $flag;
141              
142 35 50 33     294 if ($class && $class eq 'dbh') { # legacy
143 0         0 $flag = 'dbh';
144 0         0 $class = undef;
145             }
146              
147 35 50       339 my $instance = DBR::Config::Instance->lookup(
148             dbr => $self,
149             session => $self->{session},
150             handle => $name,
151             class => $class
152             ) or return $self->_error("No config found for db '$name' class '$class'");
153 35         199 return $instance;
154             }
155              
156             sub timezone{
157 0     0 0 0 my $self = shift;
158 0         0 my $tz = shift;
159 0 0       0 $self->{session}->timezone($tz) or return $self->_error('Failed to set timezone');
160             }
161              
162             sub remap{
163 0     0 0 0 my $self = shift;
164 0         0 my $class = shift;
165              
166 0 0       0 return $self->_error('class must be specified') unless $class;
167              
168 0         0 $self->{globalclass} = $class;
169              
170 0         0 return 1;
171             }
172              
173 0     0 0 0 sub unmap{ undef $_[0]->{globalclass}; return 1 }
  0         0  
174 17     17 1 141 sub flush_handles{ DBR::Config::Instance->flush_all_handles }
175 17     17   931 sub DESTROY{ $_[0]->flush_handles }
176              
177             1;
178              
179             =pod
180              
181             =head1 NAME
182              
183             DBR - Database Repository ORM (object-relational mapper).
184              
185             =head1 DESCRIPTION
186              
187             DBR (Database Repository) is a fairly directed attempt at an Object Relational Mapper.
188             It is not trying to be all things to all people. It's focus is on managing large schemas with an
189             emphasis on metadata, rather than defining schema structure with code.
190              
191             See L<DBR::Manual> for more details.
192              
193             =head1 SYNOPSIS
194              
195             use DBR ( conf => '/path/to/my/DBR.conf' );
196            
197             my $music = dbr_connect('music');
198             my $artists = $music->artist->all;
199            
200             print "Artists:\n";
201             while (my $artist = $artists->next) {
202             print "\t" . $artist->name . "\n";
203             }
204              
205             =head1 EXPORT
206              
207             use DBR (
208             conf => '/path/to/my/DBR.conf' # Required ( unless app is specified )
209            
210             # Remaining parameters are optional
211             app => 'myapp' # auto generated by default
212             use_exceptions => 1, # default
213             logpath => '/tmp/dbr_auto.log' # default
214             loglevel => 'warn' # default. allows: none info warn error debug debug2 debug3
215             );
216              
217             Note: specify parameter: app => 'myappname' to allow multiple libraries to share one connection pool.
218             Only the library loaded first needs to specify conf and the other parameters. Subsequent libraries can then specify only app => 'myappname'
219              
220             When you "use DBR" with arguments, as above, the default behavior is to export the following methods into your class
221              
222             =head2 dbr_connect( $schema [, $class] );
223              
224             Connect to an instance of the specified schema
225              
226             my $music = dbr_connect('music');
227              
228             Optionally accepts a $class argument, to specify which instance. Defaults to "master"
229              
230             Returns a L<DBR::Handle> object representing your connection handle
231              
232             =head2 dbr_instance( $schema [, $class] );
233              
234             Similar to dbr_connect, but returns a L<DBR::Config::Instance> object instead of a L<DBR::Handle> object.
235              
236             my $instance = dbr_connect('music');
237            
238             An instance object represents the instance of the database schema in question, without necessarily being connected to it.
239              
240             =head1 METHODS
241              
242             =head2 new
243              
244             Constructor. Useful in situations where you do not wish to export dbr_connect and dbr_instance into your class ( described above )
245              
246             my $logger = new DBR::Util::Logger( -logpath => 'dbr.log' );
247             my $dbr = new DBR(
248             -logger => $logger,
249             -conf => '/path/to/my/DBR.conf'
250             );
251             my $handle = $dbr->connect( 'music' );
252              
253             =head3 arguments
254              
255             =over 1
256              
257             =item -logger
258              
259             L<DBR::Util::Logger> object ( required )
260              
261             =item -conf
262              
263             path to the DBR.conf you wish to use ( required )
264              
265             =item -use_exceptions
266              
267             Boolean. Causes all DBR errors to raise an exception, rather than logging an returning false ( default )
268              
269             =item -admin
270              
271             Boolean. Enables configuration objects to write changes to metadata DB ( don't use )
272              
273             =item -fudge_tz
274              
275             Boolean. Prevents DBR from aborting in the event that it cannot determine the system timezone.
276              
277             =back
278              
279             Returns a L<DBR> object.
280              
281             =head2 connect
282              
283             Same arguments as dbr_connect above
284              
285             =head2 get_instance
286              
287             Same arguments as dbr_instance above
288              
289             =head2 flush_handles
290              
291             Disconnects all active database connections. Useful if you need to fork your process
292              
293             =cut
294