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