scopeguard almost done
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / TxnScopeGuard.pm
1 package DBIx::Class::Storage::TxnScopeGuard;
2
3 use strict;
4 use warnings;
5 use Carp::Clan qw/^DBIx::Class/;
6
7 sub new {
8   my ($class, $storage) = @_;
9
10   $storage->txn_begin;
11   bless [ 0, $storage ], ref $class || $class;
12 }
13
14 sub commit {
15   my $self = shift;
16
17   $self->[1]->txn_commit;
18   $self->[0] = 1;
19 }
20
21 sub DESTROY {
22   my ($dismiss, $storage) = @{$_[0]};
23
24   return if $dismiss;
25
26   my $exception = $@;
27
28   carp 'A DBIx::Class::Storage::TxnScopeGuard went out of scope without explicit commit or error. Rolling back.'
29     unless $exception;
30
31   my $rollback_exception;
32   {
33     local $@;
34     eval { $storage->txn_rollback };
35     $rollback_exception = $@;
36   }
37
38   if ($rollback_exception && $rollback_exception !~ /DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION/) {
39     if ($exception) {
40       $@ = "Transaction aborted: ${exception} "
41           ."Rollback failed: ${rollback_exception}";
42     }
43     else {
44       # throws an object (verified with eval{}) but DESTROY eats the exception
45       $storage->throw_exception ("Rollback failed: ${rollback_exception}");
46     }
47   }
48 }
49
50 1;
51
52 __END__
53
54 =head1 NAME
55
56 DBIx::Class::Storage::TxnScopeGuard - Scope-based transaction handling
57
58 =head1 SYNOPSIS
59
60  sub foo {
61    my ($self, $schema) = @_;
62
63    my $guard = $schema->txn_scope_guard;
64
65    # Multiple database operations here
66
67    $guard->commit;
68  }
69
70 =head1 DESCRIPTION
71
72 An object that behaves much like L<Scope::Guard>, but hardcoded to do the
73 right thing with transactions in DBIx::Class. 
74
75 =head1 METHODS
76
77 =head2 new
78
79 Creating an instance of this class will start a new transaction (by
80 implicitly calling L<DBIx::Class::Storage/txn_begin>. Expects a
81 L<DBIx::Class::Storage> object as its only argument.
82
83 =head2 commit
84
85 Commit the transaction, and stop guarding the scope. If this method is not
86 called and this object goes out of scope (i.e. an exception is thrown) then
87 the transaction is rolled back, via L<DBIx::Class::Storage/txn_rollback>
88
89 =cut
90
91 =head1 SEE ALSO
92
93 L<DBIx::Class::Schema/txn_scope_guard>.
94
95 =head1 AUTHOR
96
97 Ash Berlin, 2008.
98
99 Insipred by L<Scope::Guard> by chocolateboy.
100
101 This module is free software. It may be used, redistributed and/or modified
102 under the same terms as Perl itself.
103
104 =cut