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