NAME
SPOPS::DBI -- Implement SPOPS class, serializing into a DBI database
SYNOPSIS
use SPOPS::DBI;
@ISA = qw( SPOPS::DBI );
...
DESCRIPTION
This SPOPS class is not meant to be used directly. Instead, you inherit certain methods from it while implementing your own. Your module should implement:
(optional) Methods to sort member objects or perform operations on groups of them at once.
(optional) Methods to relate an object of this class to objects of other classes -- for instance, to find all users within a group.
(optional) The initialization method (_class_initialize()), which should create a config() object stored in the package variable and initialize it with configuration information relevant to the class.
(optional) Methods to accomplish actions before/after many of the actions implemented here: fetch/save/remove.
(optional) Methods to accomplish actions before/after saving or removing an object from the cache.
Of course, these methods can also do anything else you like. :)
As you can see, all the methods are optional. Along with SPOPS::Configure and SPOPS::Configure::DBI, you can create an entirely virtual class consisting only of configuration information. So you can actually create the implementation for a new object in two steps:
Create the configuration file (or add to the existing one)
Create the database table the class depends on.
Complete!
DATA ACCESS METHODS
The following methods access configuration information about the class but are specific to the DBI subclass.
base_table ($): Just the table name, no owners or db names prepended.
table_name ($): Fully-qualified table name
field (\%): Hashref of fields/properties (field is key, value is true)
field_list (\@): Arrayref of fields/propreties
no_insert (\%): Hashref of fields not to insert (field is key, value is true)
no_update (\%): Hashref of fields not to update (field is key, value is true)
skip_undef (\%): Hashref of fields to skip update/insert if they are undefined (field is key, value is true)
field_alter (\%): Hashref of data-formatting instructions (field is key, instruction is value)
OBJECT METHODS
id_clause( [ $id, [ $opt, \%params ] )
Returns a snippet of SQL suitable for identifying this object in the database.
This can be called either from the class or from a particular object. If called from a class, the $id value must be passed in. Examples:
my $id = 35;
my $sql = qq/
DELETE FROM $table
WHERE @{[ $class->id_clause( $id ) ]}
/;
print "SQL: $sql";
>> SQL:
DELETE FROM this_table
WHERE this_table.this_id = 35
$class->db_select( ... where => $class->id_clause( 15 ), ... )
If the system cannot determine the data type of the id field, it makes a best guess based on the package variable GUESS_ID_FIELD_TYPE. It defaults to SQL_INTEGER (as set by DBI), but you can set it dynamically as well:
$SPOPS::DBI::GUESS_ID_FIELD_TYPE = SQL_VARCHAR;
Note that the default behavior is to create a fully-qualified ID field. If you do not wish to do this (for instance, if you need to use the ID field for a lookup into a link table), just pass 'noqualify' as the second argument. To use the example from above:
my $id = 35;
my $sql = qq/
DELETE FROM $table
WHERE @{[ $class->id_clause( $id, 'noqualify' ) ]}
/;
print "SQL: $sql";
>> SQL:
DELETE FROM this_table
WHERE this_id = 35
fetch( $id, \%params )
Fetches the information for an object of type class from the data store, creates an object with the data and returns the object. Any failures trigger a die with pertinent information as described in "ERROR HANDLING".
If you have security turned on for the object class, the system will first check if the currently-configured user is allowed to fetch the object. If the user has less that SEC_LEVEL_READ access, the fetch is denied and a die() triggered.
Note that if the fetch is successful we store the access level of this object within the object itself. Check the temporary property {tmp_security_level} of any object and you will find it.
Parameters:
field_alter - (\%) fields are keys, values are database-dependent
formatting strings. You can accomplish different types of
date-formatting or other manipulation tricks.
You can also pass a DEBUG value to get debugging information for that particular statement dumped into the error log:
my $obj = eval { $class->fetch( $id, { DEBUG => 1 } ); };
fetch_group( \%params )
Returns an arrayref of objects that meet the criteria you specify.
Parameters:
where - a WHERE clause; leave this blank and you will get all entries
order - an ORDER BY clause; leave this blank and the order is
arbitrary
other parameters get passed onto the fetch() statement when the
records are being retrieved.
This is actually fairly powerful. Examples:
# Get all the user objects and put them in a hash
# indexed by the id
my %uid = map { $_->id => $_ } @{ $R->user->fetch_group( { order => 'last_name' } ) };
# Get only those user objects for people who have
# logged in today
my $users = $R->user->fetch_group( {
where => 'datediff( dd, last_login, get_date() ) = 0',
order => 'last_name'
} );
foreach my $user ( @{ $users } ) {
print "User: $user->{login_name} logged in today.\n";
}
Note that you can also return objects that match the results of a join query:
my $list = eval { $class->fetch_group( { order => 'item.this, item.that',
from => [ 'item', 'modifier' ],
where => 'modifier.property = ? AND ' .
'item.item_id = modifier.item_id',
value => [ 'property value' ], } ); };
save()
Object method that saves this object to the data store. Returns the new ID of the object if it is an add; returns the object ID if it is an update. As with other methods, any failures trigger a die().
Example:
my $obj = $class->new;
$obj->{param1} = $value1;
$obj->{param2} = $value2;
my $new_id = eval { $obj->save };
if ( $@ ) {
print "Error inserting object: $@->{error}\n";
}
else {
print "New object created with ID: $new_id\n";
}
Note that if your database schema includes something like:
CREATE TABLE my_table (
my_id int,
created_on datetime default today(),
table_legs tinyint default 4
)
and your object had the following values:
my_id => 10,
created_on => undef,
table_legs => undef
The only thing your object would reflect after inserting is the ID, since the other values are filled in by the database. The save() method tries to take this into account and syncs the object up with what is in the database once the record has been successfully inserted. If you want to skip this step, either pass a positive value for the 'no_sync' key or set 'no_save_sync' to a positive value in the CONFIG of the implementing class.
remove()
Note that you can only remove a saved object (duh). Also tries to remove the object from the cache. The object will not actually be destroyed until it goes out of scope, so do not count on its DESTROY method being called exactly when this happens.
Returns 1 on success, die() with hashref on failure. Example:
eval { $obj->remove };
if ( $@ ) {
print "Object not removed. Error: $@->{error}";
}
else {
print "Object removed properly.";
}
log_action( $action, $id )
Implemented by subclass.
This method is passed the action performed upon an object ('create', 'update', 'remove') and the ID. SPOPS::DBI comes with an empty method, but you can subclass it and do what you wish
ERROR HANDLING
Like all SPOPS classes, any errors encountered will be tossed up to the application using a die() and a simple string as a message. We also set more detailed information in a number of SPOPS::Error package variables; see that module for more details.
TO DO
BUGS
COPYRIGHT
Copyright (c) 2001 intes.net, inc.. All rights reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
AUTHORS
Chris Winters <chris@cwinters.com>