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