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