=head1 NAME DBIx::Class::Tutorial::Part3 =head1 DESCRIPTION If you missed the previous parts, go and start reading at L. Stay here if you're just after ways to deal with the data you're getting out of DBIx::Class, or adding your own accessors. =head1 GLOSSARY =over =item Inflation and Deflation The act of converting data coming out of the database, into a useful object in order to call methods on it, is called C. This is usually done for the data from one column of a Row. The classic example is a field containing data representing a specific date and time. The data type for these fields is usually C or C. An C can turn the datetime data into a L object. Deflation is the opposite. Turning a supplied object back into a string or other piece of data suitable for inserting into the database. =item Auto-Incrementing and Sequences Most databases provide a way to auto-increment a numeric column, usually an integer column, to use as a primary key. Some allow you to create a sequence which can be queried for its next value, to use as the primary key. The difficulty with creating new rows using auto-increment primary keys is retrieving the value of the key after a new row has been inserted. =item Non-column data An oft-asked question is: How can I add accessors to my Result classes to store non-column data? We can easily add new accessors to Row objects to set and retrieve data not stored in the database. =back =head1 Dealing with Primary Keys L automatically fetches the primary key from the database for you, and stores it in your new row object. ## Fetch a new path and print its ID: my $path = $schema->resultset('Path')->create( { path => '/support', } ); print $path->id; This is done using L. Tables using sequences for their primary keys should be updated using a trigger to update the value. The name of the sequence can be set in the L so that the last value can be fetched by L. =head1 Turning values into useful objects Just retrieving raw data from the database is only half the battle. You likely want to also do something useful with it, or manipulate it and re-insert. For example, many tables have a field containing the date and time the row was created, or last modified. If we want to take that date and display, for example, how long since the row was modified in days/hours/minutes, it would be useful to have that C value as a L object, then we can use L or similar to display the elapsed time. To do this, we can add a new C to the Ces. In F you'll notice a line that says: __PACKAGE__->load_components(qw/ Core/); It may contain other components as well. Add the L component in front of the existing ones. __PACKAGE__->load_components(qw/ InflateColumn::DateTime Core /); Order is important. Core must go last. The accessors of any columns of type C, C and C will now return L objects when called. ## print last_modified as an iso formatted string my $dt = $path->last_modified(); print $dt->iso_string; You can now also set the value of last_modified using a L object. ## Set last_modified my $dtnow = DateTime->now(); $path->last_modified($dtnow); $path->update(); To see how to create more inflators and deflators for other types of objects, read L. =head1 Changing the standard accessors L creates standard getter/setter accessors for you, for all your values. If you would like to change or manipulate the value of a particular column on the way into or out of the database, you can write your own accessors. To do this you will first have to edit the Result class, adding the C key in your L call. ## add accessor for path column, in ## Breadcrumbs::Schema::Path __PACKAGE__->add_columns( ... path => { data_type => 'varchar', size => 255, accessor => '_path', } .. ); DBIx::Class will now create this accessor with the name C<_path>. We can now write our own C method. ## Clean extra slashes off paths sub path { my ($self, $value) = @_; if(@_ > 1) { $value = s{^/}{}; $value = s{/$}{}; $self->_path($value); } return $self->_path(); } =head1 Adding your own data and methods You can add your own accessors for non-column (database) data to your Result classes quite easily. Just edit the Result classes. ## Add accessor for storing whether a path has been checked ## to Breadcrumbs::Schema::Path __PACKAGE__->mk_group_accessors('simple' => qw/is_checked/); $path->is_checked(1); Or, just add an entire method to do the work and return the result. ## Add method to check if the path exists: sub check { my ($self, $root) = @_; return 1 if(-d catfile($root, $self->path)); return 0; } =head1 Adding ResultSet methods Putting methods in your Result classes will make them available to the Row objects. To add methods to entire resultsets, you will first need to subclass L. package Breadcrumbs::ResultSet::Path; use base 'DBIx::Class::ResultSet'; sub check_paths { ## $self is a resultset object! my ($self, $root) = @_; my $ok = 1; foreach my $path ($self->all) { $ok = 0 if(!-d catfile($root, $path->path)); } return $ok; } To make this module your default resultset for all Path resultsets, call C in your Result class. ## Set the new resultset class, in Breadcrumbs::Schema::Path: __PACKAGE__->resultset_class('Breadcrumbs::ResultSet::Path'); Make sure you don't create the new C class in the namespace/directory underneath the existing Schema. This will cause L to attempt to load it as if it were a Result class. The result will not be good. =head1 CONCLUSIONS =head1 EXERCISES =head1 WHERE TO GO NEXT =head1 AUTHOR Jess Robinson