more documentation updates
[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
f2188d3f 11## On create/insert, add new entry to AuditLog and new content to AuditHistory
74f04ccc 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) = @_;
548cc9f7 20 return if $self->in_storage;
6bfb7a1d 21
22 my $res = $self->next::method(@args);
548cc9f7 23 $self->journal_log_insert;
6bfb7a1d 24
c5fba518 25 return $res;
74f04ccc 26}
27
548cc9f7 28sub journal_log_insert {
6bfb7a1d 29 my ($self) = @_;
30
7adb876c 31 if ( $self->in_storage ) {
32 my $j = $self->_journal_schema;
33 my $change_id = $j->journal_create_change()->id;
34 $j->journal_update_or_create_log_entry( $self, create_id => $change_id );
35 $j->journal_record_in_history( $self, audit_change_id => $change_id );
36 }
6bfb7a1d 37}
38
74f04ccc 39## On delete, update delete_id of AuditLog
40
548cc9f7 41sub delete {
42 my $self = shift;
43 $self->next::method(@_);
44 $self->journal_log_delete(@_);
6bfb7a1d 45}
1e996809 46
548cc9f7 47sub journal_log_delete {
6bfb7a1d 48 my ($self) = @_;
49
7adb876c 50 unless ($self->in_storage) {
51 my $j = $self->_journal_schema;
52 $j->journal_update_or_create_log_entry( $self, delete_id => $j->journal_create_change->id );
53 }
1e996809 54}
55
f2188d3f 56## On update, copy row's new contents to AuditHistory
74f04ccc 57
548cc9f7 58sub update {
59 my $self = shift;
548cc9f7 60 $self->next::method(@_);
f2188d3f 61 $self->journal_log_update(@_);
6bfb7a1d 62}
63
548cc9f7 64sub journal_log_update {
65 my $self = shift;
1e996809 66
3ef10e31 67 if ($self->in_storage) {
7adb876c 68 my $j = $self->_journal_schema;
e0a0e192 69 my $change_id = $j->journal_create_change->id;
3ef10e31 70 $j->journal_record_in_history( $self, audit_change_id => $change_id );
1e996809 71 }
1e996809 72}
73
ec16e73a 74=head1 NAME
75
86e977a3 76DBIx::Class::Journal - Auditing for tables managed by DBIx::Class
ec16e73a 77
78=head1 SYNOPSIS
79
22f043c8 80 package My::Schema;
81 use base 'DBIx::Class::Schema';
ec16e73a 82
22f043c8 83 __PACKAGE__->load_components(qw/Schema::Journal/);
ec16e73a 84
86e977a3 85And then call C<< $schema->journal_schema_deploy >> to create all the tables
86necessary for the journal, in your database.
87
b468e28b 88Optionally set where the journal is stored:
86e977a3 89
22f043c8 90 __PACKAGE__->journal_connection(['dbi:SQLite:t/var/Audit.db']);
ec16e73a 91
b468e28b 92Later on, in your application, wrap operations in transactions, and optionally
93associate a user with the changeset:
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
ec16e73a 100=head1 DESCRIPTION
101
102The purpose of this L<DBIx::Class> component module is to create an
103audit-trail for all changes made to the data in your database (via a
b468e28b 104DBIx::Class schema). It creates I<changesets> and assigns each
105create/update/delete operation an I<id>. The creation and deletion date of
106each row is stored, as well as the historical contents of any row that gets
107changed.
ec16e73a 108
22f043c8 109All queries which need auditing must be called using
b468e28b 110L<DBIx::Class::Schema/txn_do>, which is used to create changesets for each
111transaction.
ec16e73a 112
b468e28b 113To track who did which changes, the C<user_id> (an integer) of the current
114user can be set, and a C<session_id> can also be set; both are optional.
ec16e73a 115
b468e28b 116To access the auditing schema to look at the auditdata or revert a change, use
117C<< $schema->_journal_schema >>.
ec16e73a 118
b468e28b 119=head1 DEPLOYMENT
ec16e73a 120
b468e28b 121Currently the module expects to be deployed alongside a new database schema,
122and track all changes from first entry. Do do that you need to add some tables
123for the journal, and you can configure which tables have their operations
124journalled by the module.
ec16e73a 125
b468e28b 126Connect to your schema and deploy the journal tables as below. The module
127automatically scans your schema and sets up storage for journal entries.
ec16e73a 128
b468e28b 129 My::Schema->journal_sources([qw/ table1 table2 /]);
130
131 $schema = My::Schema->connect(...);
132 $schema->journal_schema_deploy;
ec16e73a 133
b468e28b 134Note that if you are retrofitting journalling to an existing database, then as
135well as creating the journal you will need to populate it with a history so
136that when rows are deleted they can be mapped back to a (fake) creation.
ec16e73a 137
b468e28b 138=head1 TABLES
139
140The journal schema contains a number of tables. These track row creation,
141update and deletion, and also are aware of multiple operations taking place
142within one transaction.
143
144=over 4
145
146=item ChangeSet
147
148Each changeset row has an auto-incremented C<ID>, optional C<user_id> and
149C<session_id>, and a C<set_date> which defaults to the current datetime. This
150is the authoritative log of one discrete change to your database, which may
151possible consist of a number of ChangeLog operations within a single
152transaction.
ec16e73a 153
41daf590 154=item ChangeLog
ec16e73a 155
b468e28b 156Each operation done within the transaction is recorded as a row in the
157ChangeLog table. It contains an auto-incrementing C<ID>, the C<changeset_id>
158and an C<order> column to establish the order in which changes took place.
ec16e73a 159
160=item AuditLog
161
b468e28b 162For every table in the original database that is to be audited, an AuditLog
163table is created. When a row appears in the original database a corresponding
164row is added here with a ChangeLog ID in the C<create_id> column, and when
165that original row is deleted the AuditLog is updated to add another ChangeLog
166ID this time into the C<delete_id> column. A third id column contains the
167primary key of the original row, so you can find it in the AuditHistory.
168
169Note that currently only integer-based single column primary keys are
170supported in your original database tables.
ec16e73a 171
172=item AuditHistory
173
b468e28b 174For every table in the original database to be audited, an AuditHistory table
175is created. This is where the actual field data from your original table rows
176are stored on creation and on each update.
177
178Each row in the AuditHistory has a C<change_id> field containing the ID of the
179ChangeLog row. The other fields correspond to all the fields from the original
180table (with any constraints removed). Each time a column value in the original
181table is changed, the entire row contents after the change are added as a new
182row in this table.
ec16e73a 183
184=back
185
b468e28b 186=head1 CLASS METHODS
187
188Call these in your Schema Class such as the C<My::Schema> package file, as in
189the SYNOPSIS, above.
ec16e73a 190
b468e28b 191=over 4
ec16e73a 192
c1c87879 193=item journal_connection \@connect_info
ec16e73a 194
b468e28b 195Set the connection information for the database to save your audit information
196to.
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
27e45f70 202=item journal_components @components
203
204If you want to add components to your journal
86e977a3 205(L<DBIx::Class::Schema::Versioned> for example) pass them here.
27e45f70 206
c1c87879 207=item journal_sources \@source_names
ec16e73a 208
b468e28b 209Set a list of source names you would like to audit. If unset, all sources are
210used.
ec16e73a 211
b468e28b 212NOTE: Currently only sources with a single-column integer PK are supported, so
213use this method if you have sources which don't comply with that limitation.
ec16e73a 214
c1c87879 215=item journal_storage_type $type
ec16e73a 216
ec16e73a 217Enter the special storage type of your journal schema if needed. See
218L<DBIx::Class::Storage::DBI> for more information on storage types.
219
c1c87879 220=item journal_user \@rel
ec16e73a 221
b468e28b 222The user_id column in the L</ChangeSet> will be linked to your user id with a
223C<belongs_to> relation, if this is set with the appropriate arguments. For
224example:
225
226 __PACKAGE__->journal_user(['My::Schema::User', {'foreign.userid' => 'self.user_id'}]);
227
228=back
229
230=head1 OBJECT METHODS
231
232Once you have a connection to your database, call these methods to manage the
233journalling.
234
235=over 4
ec16e73a 236
86e977a3 237=item journal_schema_deploy
238
b468e28b 239Will use L<DBIx::Class::Schema/deploy> to set up the tables for journalling in
240your schema. Use this method to set up your journal.
241
242Note that if you are retrofitting journalling to an existing database, then as
243well as creating the journal you will need to populate it with a history so
244that when rows are deleted they can be mapped back to a (fake) creation.
86e977a3 245
c1c87879 246=item journal_deploy_on_connect $bool
ec16e73a 247
c1c87879 248If set to a true value will cause C<journal_schema_deploy> to be called on
249C<connect>.
ec16e73a 250
86e977a3 251Not recommended, but present for backwards compatibility.
ec16e73a 252
c1c87879 253=item changeset_user $user_id
ec16e73a 254
b468e28b 255Set the C<user_id> for the following changeset(s). This must be an integer.
ec16e73a 256
c1c87879 257=item changeset_session $session_id
ec16e73a 258
b468e28b 259Set the C<session_id> for the following changeset(s). This must be an integer.
ec16e73a 260
86e977a3 261=item deploy
262
b468e28b 263Overloaded L<DBIx::Class::Schema/deploy> which will deploy your original
86e977a3 264database schema and following that will deploy the journal schema.
265
c1c87879 266=item txn_do $code_ref, @args
ec16e73a 267
b468e28b 268Overloaded L<DBIx::Class::Schema/txn_do>, this must be used to start a new
269ChangeSet to cover a group of changes. Each subsequent change to an audited
270table will use the C<changeset_id> created in the most recent C<txn_do> call.
ec16e73a 271
c1c87879 272Currently nested C<txn_do> calls cause a single ChangeSet object to be created.
273
90dae731 274=back
275
ec16e73a 276=head1 SEE ALSO
277
b468e28b 278=over 4
279
280=item *
281
ec16e73a 282L<DBIx::Class> - You'll need it to use this.
283
b468e28b 284=back
ec16e73a 285
b468e28b 286=head1 LIMITATIONS
287
288=over 4
289
290=item *
291
292Only single-column integer primary key'd tables are supported for auditing.
293
294=item *
ec16e73a 295
296Updates made via L<DBIx::Class::ResultSet/update> are not yet supported.
297
b468e28b 298=item *
299
ec16e73a 300No API for viewing or restoring changes yet.
301
b468e28b 302=back
303
304Patches for the above are welcome ;-)
ec16e73a 305
306=head1 AUTHOR
307
308Jess Robinson <castaway@desert-island.me.uk>
309
310Matt S. Trout <mst@shadowcatsystems.co.uk> (ideas and prodding)
311
312=head1 LICENCE
313
314You may distribute this code under the same terms as Perl itself.
f0f14c64 315
ec16e73a 316=cut
f0f14c64 317
3181;