Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 07d690e4

Von Moritz Bunkus vor mehr als 13 Jahren hinzugefügt

  • ID 07d690e4c520994e05ba6aa89ee1b5b1c82bbcd4
  • Vorgänger c73b2658
  • Nachfolger d49485e0

Framework für after/before-Hooks bei load/save/delete

Conflicts:

SL/X.pm

Unterschiede anzeigen:

SL/DB/Object.pm
9 9
use SL::DB::Helper::Attr;
10 10
use SL::DB::Helper::Metadata;
11 11
use SL::DB::Helper::Manager;
12
use SL::DB::Object::Hooks;
12 13

  
13 14
use base qw(Rose::DB::Object);
14 15

  
......
94 95
  return $check ? $self->$sub(@_) : $self;
95 96
}
96 97

  
98
# These three functions cannot sit in SL::DB::Object::Hooks because
99
# mixins don't deal well with super classes (SUPER is the current
100
# package's super class, not $self's).
101
sub load {
102
  my ($self, @args) = @_;
103

  
104
  SL::DB::Object::Hooks::run_hooks($self, 'before_load');
105
  my $result = $self->SUPER::load(@args);
106
  SL::DB::Object::Hooks::run_hooks($self, 'after_load', $result);
107

  
108
  return $result;
109
}
110

  
111
sub save {
112
  my ($self, @args) = @_;
113
  my $worker        = sub {
114
    SL::DB::Object::Hooks::run_hooks($self, 'before_save');
115
    my $result = $self->SUPER::save(@args);
116
    SL::DB::Object::Hooks::run_hooks($self, 'after_save', $result);
117
  };
118

  
119
  return $self->db->in_transaction ? $worker->() : $self->db->do_transaction($worker);
120
}
121

  
122
sub delete {
123
  my ($self, @args) = @_;
124
  my $worker        = sub {
125
    SL::DB::Object::Hooks::run_hooks($self, 'before_delete');
126
    my $result = $self->SUPER::delete(@args);
127
    SL::DB::Object::Hooks::run_hooks($self, 'after_delete', $result);
128
  };
129

  
130
  return $self->db->in_transaction ? $worker->() : $self->db->do_transaction($worker);
131
}
132

  
97 133
1;
98 134

  
99 135
__END__
SL/DB/Object/Hooks.pm
1
package SL::DB::Object::Hooks;
2

  
3
use strict;
4

  
5
use SL::X;
6

  
7
use parent qw(Exporter);
8
our @EXPORT = qw(before_load   after_load
9
                 before_save   after_save
10
                 before_delete after_delete);
11

  
12
my %hooks;
13

  
14
# Adding hooks
15

  
16
sub before_save {
17
  _add_hook('before_save', @_);
18
}
19

  
20
sub after_save {
21
  _add_hook('after_save', @_);
22
}
23

  
24
sub before_load {
25
  _add_hook('before_load', @_);
26
}
27

  
28
sub after_load {
29
  _add_hook('after_load', @_);
30
}
31

  
32
sub before_delete {
33
  _add_hook('before_delete', @_);
34
}
35

  
36
sub after_delete {
37
  _add_hook('after_delete', @_);
38
}
39

  
40
# Running hooks
41

  
42
sub run_hooks {
43
  my ($object, $when, @args) = @_;
44

  
45
  foreach my $sub (@{ ( $hooks{$when} || { })->{ ref($object) } || [ ] }) {
46
    my $result = ref($sub) eq 'CODE' ? $sub->($object, @args) : $object->call_sub($sub, @args);
47
    SL::X::DBHookError->throw(error => "${when} hook '" . (ref($sub) eq 'CODE' ? '<anonymous sub>' : $sub) . "' failed") if !$result;
48
  }
49
}
50

  
51
# Internals
52

  
53
sub _add_hook {
54
  my ($when, $class, $sub_name, $code) = @_;
55
  $hooks{$when}           ||= { };
56
  $hooks{$when}->{$class} ||= [ ];
57
  push @{ $hooks{$when}->{$class} }, $sub_name;
58
}
59

  
60
1;
61
__END__
62

  
63
=pod
64

  
65
=encoding utf8
66

  
67
=head1 NAME
68

  
69
SL::DB::Object::Hooks - Hooks that are run before/after a
70
load/save/delete
71

  
72
=head1 SYNOPSIS
73

  
74
Hooks are functions that are called before or after an object is
75
loaded, saved or deleted. The package defines the hooks, and those
76
hooks themselves are run as instance methods.
77

  
78
Hooks are run in the order they're added.
79

  
80
Hooks must return a trueish value in order to continue processing. If
81
any hook returns a falsish value then an exception (instance of
82
C<SL::X::DBHookError>) is thrown. However, C<SL::DB::Object> usually
83
runs the hooks from within a transaction, catches the exception and
84
only returns falsish in error cases.
85

  
86
=head1 FUNCTIONS
87

  
88
=over 4
89

  
90
=item C<before_load $sub>
91

  
92
=item C<before_save $sub>
93

  
94
=item C<before_delete $sub>
95

  
96
=item C<after_load $sub>
97

  
98
=item C<after_save $sub>
99

  
100
=item C<after_delete $sub>
101

  
102
Adds a new hook that is called at the appropriate time. C<$sub> can be
103
either a name of an existing sub or a code reference. If it is a code
104
reference then the then-current C<$self> will be passed as the first
105
argument.
106

  
107
C<before> hooks are called without arguments.
108

  
109
C<after> hooks are called with a single argument: the result of the
110
C<save> or C<delete> operation.
111

  
112
=item C<run_hooks $object, $when, @args>
113

  
114
Runs all hooks for the object C<$object> that are defined for
115
C<$when>. C<$when> is the same as one of the C<before_xyz> or
116
C<after_xyz> function names above.
117

  
118
An exception of C<SL::X::DBHookError> is thrown if any of the hooks
119
returns a falsish value.
120

  
121
This function is supposed to be called by L</SL::DB::Object::load>,
122
L</SL::DB::Object::save> or L</SL::DB::Object::delete>.
123

  
124
=back
125

  
126
=head1 EXPORTS
127

  
128
This mixin exports the functions L</before_load>, L</after_load>,
129
L</before_save>, L</after_save>, L</before_delete>, L</after_delete>.
130

  
131
=head1 BUGS
132

  
133
Nothing here yet.
134

  
135
=head1 AUTHOR
136

  
137
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
138

  
139
=cut
SL/X.pm
5 5
use Exception::Lite qw(declareExceptionClass);
6 6

  
7 7
declareExceptionClass('SL::X::FormError');
8
declareExceptionClass('SL::X::DBHookError');
8 9

  
9 10
1;

Auch abrufbar als: Unified diff