7 use English qw(-no_match_vars);
 
   9 use Rose::DBx::Cache::Anywhere;
 
  11 use base qw(Rose::DB);
 
  13 __PACKAGE__->db_cache_class('Rose::DBx::Cache::Anywhere');
 
  14 __PACKAGE__->use_private_registry;
 
  21   # runtime require to break circular include
 
  22   require SL::DBConnect;
 
  23   return SL::DBConnect->connect(@_);
 
  27   my $domain = shift || SL::DB->default_domain;
 
  28   my $type   = shift || SL::DB->default_type;
 
  30   ($domain, $type) = _register_db($domain, $type);
 
  32   my $db = __PACKAGE__->new_or_cached(domain => $domain, type => $type);
 
  38   create(undef, 'KIVITENDO');
 
  42   create(undef, 'KIVITENDO_AUTH');
 
  49   require SL::DBConnect;
 
  50   my %specific_connect_settings;
 
  51   my %common_connect_settings = (
 
  53     european_dates   => ((SL::DBConnect->get_datestyle || '') =~ m/european/i) ? 1 : 0,
 
  59   if (($type eq 'KIVITENDO_AUTH') && $::auth && $::auth->{DB_config} && $::auth->session_tables_present) {
 
  60     %specific_connect_settings = (
 
  61       database        => $::auth->{DB_config}->{db},
 
  62       host            => $::auth->{DB_config}->{host} || 'localhost',
 
  63       port            => $::auth->{DB_config}->{port} || 5432,
 
  64       username        => $::auth->{DB_config}->{user},
 
  65       password        => $::auth->{DB_config}->{password},
 
  68   } elsif ($::auth && $::auth->client) {
 
  69     my $client        = $::auth->client;
 
  70     %specific_connect_settings = (
 
  71       database        => $client->{dbname},
 
  72       host            => $client->{dbhost} || 'localhost',
 
  73       port            => $client->{dbport} || 5432,
 
  74       username        => $client->{dbuser},
 
  75       password        => $client->{dbpasswd},
 
  78   } elsif (%::myconfig && $::myconfig{dbname}) {
 
  79     %specific_connect_settings = (
 
  80       database        => $::myconfig{dbname},
 
  81       host            => $::myconfig{dbhost} || 'localhost',
 
  82       port            => $::myconfig{dbport} || 5432,
 
  83       username        => $::myconfig{dbuser},
 
  84       password        => $::myconfig{dbpasswd},
 
  88     $type = 'KIVITENDO_EMPTY';
 
  91   my %connect_settings   = (%common_connect_settings, %specific_connect_settings);
 
  92   my %flattened_settings = _flatten_settings(%connect_settings);
 
  94   $domain                = 'KIVITENDO' if $type =~ m/^KIVITENDO/;
 
  95   $type                 .= join($SUBSCRIPT_SEPARATOR, map { ($_, $flattened_settings{$_} || '') } sort grep { $_ ne 'dbpasswd' } keys %flattened_settings);
 
  96   my $idx                = "${domain}::${type}";
 
  98   if (!$_db_registered{$idx}) {
 
  99     $_db_registered{$idx} = 1;
 
 101     __PACKAGE__->register_db(domain => $domain,
 
 107   return ($domain, $type);
 
 110 sub _flatten_settings {
 
 114   while (my ($key, $value) = each %settings) {
 
 115     if ('HASH' eq ref $value) {
 
 116       %flattened = ( %flattened, _flatten_settings(%{ $value }) );
 
 118       $flattened{$key} = $value;
 
 125 sub with_transaction {
 
 126   my ($self, $code, @args) = @_;
 
 128   return $code->(@args) if $self->in_transaction;
 
 131     return $self->do_transaction(sub { @result = $code->(@args) }) ? @result : ();
 
 135     return $self->do_transaction(sub { $result = $code->(@args) }) ? $result : undef;
 
 148 SL::DB - Database access class for all RDB objects
 
 154 =item C<create $domain, $type>
 
 156 Registers the database information with Rose, creates a cached
 
 157 connection and executes initial SQL statements. Those can include
 
 158 setting the time & date format to the user's preferences.
 
 160 =item C<dbi_connect $dsn, $login, $password, $options>
 
 162 Forwards the call to L<SL::DBConnect/connect> which connects to the
 
 163 database. This indirection allows L<SL::DBConnect/connect> to route
 
 164 the calls through L<DBIx::Log4Perl> if this is enabled in the
 
 167 =item C<with_transaction $code_ref, @args>
 
 169 Executes C<$code_ref> with parameters C<@args> within a transaction,
 
 170 starting one only if none is currently active. Example:
 
 172   return $self->db->with_transaction(sub {
 
 173     # do stuff with $self
 
 176 There are two big differences between C<with_transaction> and
 
 177 L<Rose::DB/do_transaction>: the handling of an already-running
 
 178 transaction and the handling of return values.
 
 180 The first difference revolves around when a transaction is started and
 
 181 committed/rolled back. Rose's C<do_transaction> will always start one,
 
 182 then execute the code reference and commit afterwards (or roll back if
 
 183 an exception occurs).
 
 185 This prevents the caller from combining several pieces of code using
 
 186 C<do_transaction> reliably as results committed by an inner
 
 187 transaction will be permanent even if the outer transaction is rolled
 
 190 Therefore our C<with_transaction> works differently: it will only
 
 191 start a transaction if no transaction is currently active on the
 
 194 The second big difference to L<Rose::DB/do_transaction> is the
 
 195 handling of returned values. Basically our C<with_transaction> will
 
 196 return the values that the code reference C<$code_ref> returns (or
 
 197 C<undef> if the transaction was rolled back). Rose's C<do_transaction>
 
 198 on the other hand will only return a value signaling the transaction's
 
 205 =item * If a transaction is already active then C<with_transaction>
 
 206 will simply return the result of calling C<$code_ref> as-is preserving
 
 209 =item * If no transaction is started then C<$code_ref> will be wrapped
 
 210 in one. C<with_transaction>'s return value depends on the result of
 
 211 that transaction. If the it succeeds then the return value of
 
 212 C<$code_ref> will be returned preserving context. Otherwise C<undef>
 
 213 will be returned in scalar context and an empty list in list context.
 
 217 So if you want to differentiate between "transaction failed" and
 
 218 "succeeded" then your C<$code_ref> should never return C<undef>
 
 229 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>