Bug 14778: Make sure the dbh returned is checked by DBIC
[koha.git] / Koha / Database.pm
1 package Koha::Database;
2
3 # Copyright 2013 Catalyst IT
4 # chrisc@catalyst.net.nz
5 #
6 # This file is part of Koha.
7 #
8 # Koha is free software; you can redistribute it and/or modify it under the
9 # terms of the GNU General Public License as published by the Free Software
10 # Foundation; either version 3 of the License, or (at your option) any later
11 # version.
12 #
13 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
14 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License along
18 # with Koha; if not, write to the Free Software Foundation, Inc.,
19 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 =head1 NAME
22
23 Koha::Database
24
25 =head1 SYNOPSIS
26
27   use Koha::Database;
28   my $database = Koha::Database->new();
29   my $schema = $database->schema();
30
31 =head1 FUNCTIONS
32
33 =cut
34
35 use Modern::Perl;
36 use Carp;
37 use C4::Context;
38 use base qw(Class::Accessor);
39
40 use vars qw($database);
41
42 __PACKAGE__->mk_accessors(qw( ));
43
44 # _new_schema
45 # Internal helper function (not a method!). This creates a new
46 # database connection from the data given in the current context, and
47 # returns it.
48 sub _new_schema {
49
50     require Koha::Schema;
51
52     my $context = C4::Context->new();
53
54     my $db_driver = $context->{db_driver};
55
56     my $db_name   = $context->config("database");
57     my $db_host   = $context->config("hostname");
58     my $db_port   = $context->config("port") || '';
59     my $db_user   = $context->config("user");
60     my $db_passwd = $context->config("pass");
61
62     my ( %encoding_attr, $encoding_query, $tz_query );
63     my $tz = $ENV{TZ};
64     if ( $db_driver eq 'mysql' ) {
65         %encoding_attr = ( mysql_enable_utf8 => 1 );
66         $encoding_query = "set NAMES 'utf8'";
67         $tz_query = qq(SET time_zone = "$tz") if $tz;
68     }
69     elsif ( $db_driver eq 'Pg' ) {
70         $encoding_query = "set client_encoding = 'UTF8';";
71         $tz_query = qq(SET TIME ZONE = "$tz") if $tz;
72     }
73     my $schema = Koha::Schema->connect(
74         {
75             dsn => "dbi:$db_driver:database=$db_name;host=$db_host;port=$db_port",
76             user => $db_user,
77             password => $db_passwd,
78             %encoding_attr,
79             RaiseError => $ENV{DEBUG} ? 1 : 0,
80             unsafe => 1,
81             on_connect_do => [
82                 $encoding_query || (),
83                 $tz_query || (),
84             ]
85         }
86     );
87
88     my $dbh = $schema->storage->dbh;
89     eval {
90         $dbh->{RaiseError} = 1;
91         $dbh->do(q|
92             SELECT * FROM systempreferences WHERE 1 = 0 |
93         );
94         $dbh->{RaiseError} = $ENV{DEBUG} ? 1 : 0;
95     };
96     $dbh->{RaiseError} = 0 if $@;
97
98     return $schema;
99 }
100
101 =head2 schema
102
103     $schema = $database->schema;
104
105 Returns a database handle connected to the Koha database for the
106 current context. If no connection has yet been made, this method
107 creates one, and connects to the database.
108
109 This database handle is cached for future use: if you call
110 C<$database-E<gt>schema> twice, you will get the same handle both
111 times. If you need a second database handle, use C<&new_schema> and
112 possibly C<&set_schema>.
113
114 =cut
115
116 sub schema {
117     my $self = shift;
118     my $params = shift;
119
120     unless ( $params->{new} ) {
121         return $database->{schema} if defined $database->{schema};
122     }
123
124     $database->{schema} = &_new_schema();
125     return $database->{schema};
126 }
127
128 =head2 new_schema
129
130   $schema = $database->new_schema;
131
132 Creates a new connection to the Koha database for the current context,
133 and returns the database handle (a C<DBI::db> object).
134
135 The handle is not saved anywhere: this method is strictly a
136 convenience function; the point is that it knows which database to
137 connect to so that the caller doesn't have to know.
138
139 =cut
140
141 #'
142 sub new_schema {
143     my $self = shift;
144
145     return &_new_schema();
146 }
147
148 =head2 set_schema
149
150   $my_schema = $database->new_schema;
151   $database->set_schema($my_schema);
152   ...
153   $database->restore_schema;
154
155 C<&set_schema> and C<&restore_schema> work in a manner analogous to
156 C<&set_context> and C<&restore_context>.
157
158 C<&set_schema> saves the current database handle on a stack, then sets
159 the current database handle to C<$my_schema>.
160
161 C<$my_schema> is assumed to be a good database handle.
162
163 =cut
164
165 sub set_schema {
166     my $self       = shift;
167     my $new_schema = shift;
168
169     # Save the current database handle on the handle stack.
170     # We assume that $new_schema is all good: if the caller wants to
171     # screw himself by passing an invalid handle, that's fine by
172     # us.
173     push @{ $database->{schema_stack} }, $database->{schema};
174     $database->{schema} = $new_schema;
175 }
176
177 =head2 restore_schema
178
179   $database->restore_schema;
180
181 Restores the database handle saved by an earlier call to
182 C<$database-E<gt>set_schema>.
183
184 =cut
185
186 sub restore_schema {
187     my $self = shift;
188
189     if ( $#{ $database->{schema_stack} } < 0 ) {
190
191         # Stack underflow
192         die "SCHEMA stack underflow";
193     }
194
195     # Pop the old database handle and set it.
196     $database->{schema} = pop @{ $database->{schema_stack} };
197
198     # FIXME - If it is determined that restore_context should
199     # return something, then this function should, too.
200 }
201
202 =head2 EXPORT
203
204 None by default.
205
206
207 =head1 AUTHOR
208
209 Chris Cormack, E<lt>chrisc@catalyst.net.nzE<gt>
210
211 =cut
212
213 1;
214
215 __END__