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