copied wrong plan number
[dbsrgits/DBIx-Class-Journal.git] / lib / DBIx / Class / Journal.pm
CommitLineData
f0f14c64 1package DBIx::Class::Journal;
2
3use base qw/DBIx::Class/;
f0f14c64 4
ec16e73a 5use strict;
6use warnings;
7
6556c24e 8our $VERSION = '0.02_01';
ec16e73a 9
74f04ccc 10## On create/insert, add new entry to AuditLog
11
c5fba518 12# sub new
13# {
14# my ($class, $attrs, @rest) = @_;
74f04ccc 15
c5fba518 16# $class->result_source->schema->_journal_schema->current_user(delete $attrs->{user_id});
74f04ccc 17
c5fba518 18# $class->next::method($attrs, @rest);
19# }
74f04ccc 20
6bfb7a1d 21sub journal_update_or_create_log_entry
74f04ccc 22{
6bfb7a1d 23 my ($self, $field ) = @_;
24 my $rs = $self->result_source;
25 my $s_name = $rs->source_name();
74f04ccc 26
6bfb7a1d 27 my $jschema = $rs->schema->_journal_schema;
28
29 my $al = $jschema->resultset("${s_name}AuditLog");
5c9840d8 30
6bfb7a1d 31 my %id = map { $_ => $self->get_column($_)} $self->primary_columns;
5c9840d8 32
6bfb7a1d 33 my %extra;
5c9840d8 34
6bfb7a1d 35 if ( $field ) {
36 $extra{$field} = $jschema->journal_create_change->id;
b5851590 37 }
c5fba518 38
6bfb7a1d 39 $al->update_or_create({ %extra, %id });
40}
41
42sub insert
43{
44 my ($self, @args) = @_;
45
46 return if($self->in_storage);
47
48 my $res = $self->next::method(@args);
49
50 $self->journal_log_insert();
51
c5fba518 52 return $res;
74f04ccc 53}
54
6bfb7a1d 55sub journal_log_insert
56{
57 my ($self) = @_;
58
59 $self->journal_update_or_create_log_entry('create_id')
60 if $self->in_storage;
61}
62
74f04ccc 63## On delete, update delete_id of AuditLog
64
1e996809 65sub delete
66{
67 my ($self, @rest) = @_;
68 $self->next::method(@rest);
6bfb7a1d 69 $self->journal_log_delete(@rest);
70}
1e996809 71
6bfb7a1d 72sub journal_log_delete
73{
74 my ($self) = @_;
75
76 $self->journal_update_or_create_log_entry('delete_id')
77 unless $self->in_storage;
1e996809 78}
79
74f04ccc 80## On update, copy previous row's contents to AuditHistory
81
1e996809 82sub update
83{
84 my ($self, $upd, @rest) = @_;
6bfb7a1d 85 $self->journal_log_update($upd, @rest);
86 $self->next::method($upd, @rest);
87}
88
89sub journal_log_update
90{
91 my ($self, $upd, @rest) = @_;
1e996809 92
93 if($self->in_storage)
94 {
95 my $s_name = $self->result_source->source_name();
96 my $ah = $self->result_source->schema->_journal_schema->resultset("${s_name}AuditHistory");
97
98 my $obj = $self->result_source->resultset->find( $self->ident_condition );
99 $ah->create({
41daf590 100 $obj->get_columns,
101 change => { changeset_id => $ah->result_source->schema->current_changeset },
102 });
1e996809 103 }
1e996809 104}
105
ec16e73a 106=head1 NAME
107
108DBIx::Class::Journal - auditing for tables managed by DBIx::Class
109
110=head1 SYNOPSIS
111
112 package My::Schema;
113 use base 'DBIx::Class::Schema';
114
115 __PACKAGE__->load_components(qw/+DBIx::Class::Schema::Journal/);
116
117 __PACKAGE__->journal_connection(['dbi:SQLite:t/var/Audit.db']);
118 __PACKAGE__->journal_user(['My::Schema::User', {'foreign.userid' => 'self.user_id'}]);
119
120
121 ########
122
123 $schema->changeset_user($user->id);
124 my $new_artist = $schema->txn_do( sub {
125 return = $schema->resultset('Artist')->create({ name => 'Fred' });
126 });
127
128
129=head1 DESCRIPTION
130
131The purpose of this L<DBIx::Class> component module is to create an
132audit-trail for all changes made to the data in your database (via a
133DBIx::Class schema). It creates changesets and assigns each
134create/update/delete operation an id. The creation and deletion date
135of each row is stored, as well as the previous contents of any row
136that gets changed.
137
138All queries which want auditing should be called using
139L<DBIx::Class::Schema/txn_do>, which is used to create changesets for
140each transaction.
141
142To track who did which changes, the user_id (an integer) of the
143current user can be set, a session_id can also be set, both are
144optional.
145
146To access the auditing schema to look at the auditdata or revert a
147change, use C<< $schema->_journal_schema >>.
148
149=head2 TABLES
150
151The journal schema contains a number of tables.
152
153=over
154
155=item ChangeSet
156
157Each changeset row has an auto-incremented ID, optional user_id and
158session_id, and a set_date which defaults to the current datetime.
159
160A ChangeSet has_many Changes.
161
41daf590 162=item ChangeLog
ec16e73a 163
164Each change/operation done in the transaction is recorded as a row in
41daf590 165the ChangeLog table. It contains an auto-incrementing ID, the
ec16e73a 166changeset_id and an order column for the ordering of each change in
167the changeset.
168
169=item AuditLog
170
171For every table in the original database that is to be audited, an
172AuditLog table is created. Each auditlog row has an id which will
173contain the primary key of the table it is associated with. (NB:
174currently only supports integer-based single column PKs). The
175create_id and delete_id fields contain the IDs of the Changes that
176created or deleted this row.
177
178=item AuditHistory
179
180For every table in the original database to be audited, an
181AuditHistory table is created. Each row has a change_id field
41daf590 182containing the ID of the ChangeLog row. The other fields correspond to
ec16e73a 183all the fields from the original table. Each time a column value in
184the original table is changed, the entire row contents before the
185change are added as a new row in this table.
186
187=back
188
189=head2 METHODS
190
191=over
192
c1c87879 193=item journal_connection \@connect_info
ec16e73a 194
ec16e73a 195Set the connection information for the database to save your audit
c1c87879 196information to.
ec16e73a 197
c1c87879 198Leaving this blank assumes you want to store the audit data into your current
199database. The storage object will be shared by the regular schema and the
200journalling schema.
ec16e73a 201
c1c87879 202=item journal_sources \@source_names
ec16e73a 203
ec16e73a 204Set a list of source names you would like to audit, if unset, all
205sources are used.
206
207NOTE: Currently only sources with a single-column PK are supported, so
208use this method if you have sources with multi-column PKs.
209
c1c87879 210=item journal_storage_type $type
ec16e73a 211
ec16e73a 212Enter the special storage type of your journal schema if needed. See
213L<DBIx::Class::Storage::DBI> for more information on storage types.
214
c1c87879 215=item journal_user \@rel
ec16e73a 216
ec16e73a 217The user_id column in the L</ChangeSet> will be linked to your user id
218with a belongs_to relation, if this is set with the appropriate
219arguments.
220
c1c87879 221=item journal_deploy_on_connect $bool
ec16e73a 222
c1c87879 223If set to a true value will cause C<journal_schema_deploy> to be called on
224C<connect>.
ec16e73a 225
c1c87879 226Not reccomended, but present for backwards compatibility.
ec16e73a 227
c1c87879 228=item changeset_user $user_id
ec16e73a 229
c1c87879 230Set the user_id for the following changeset(s). This must be an integer.
ec16e73a 231
c1c87879 232=item changeset_session $session_id
ec16e73a 233
c1c87879 234Set the session_id for the following changeset(s). This must be an integer.
ec16e73a 235
c1c87879 236=item txn_do $code_ref, @args
ec16e73a 237
238Overloaded L<DBIx::Class::Schema/txn_do>, this must be used to start a
239new changeset to cover a group of changes. Each subsequent change to
240an audited table will use the changeset_id created in the most recent
241txn_do call.
242
c1c87879 243Currently nested C<txn_do> calls cause a single ChangeSet object to be created.
244
90dae731 245=back
246
ec16e73a 247=head1 SEE ALSO
248
249L<DBIx::Class> - You'll need it to use this.
250
251=head1 NOTES
252
253Only single-column integer primary key'd tables are supported for auditing so far.
254
255Updates made via L<DBIx::Class::ResultSet/update> are not yet supported.
256
257No API for viewing or restoring changes yet.
258
259Patches for the above welcome ;)
260
261=head1 AUTHOR
262
263Jess Robinson <castaway@desert-island.me.uk>
264
265Matt S. Trout <mst@shadowcatsystems.co.uk> (ideas and prodding)
266
267=head1 LICENCE
268
269You may distribute this code under the same terms as Perl itself.
f0f14c64 270
ec16e73a 271=cut
f0f14c64 272
2731;