NAME
DBIx::Objects - Perl extension to ease creation of database-bound objects
SYNOPSIS
This module is intended to provide an object-oriented framework for accessing data sources. The source of the data is completely abstract, allowing for complete flexibility for the data back-end. This module is NOT intended to provide a persistance layer - please use another module (like TANGRAMS) if you require object persistance.
I'm really not sure how to go about documenting this library, so let me start by explaining the history of why it was written
BACKGROUND
I developed this module when I began to notice that most of my web-applications followed a very similar format - there was a data back end and web methods which could interoperate with them. When I started to need helper applications to work with the web-apps, I started porting all of my applications to use 2 layers. The lower layer was an object framework which contained the Perl code needed to work with the database. This way, I could be sure that all of the helper applications, and of course the web application, all used the same access methods to get to the database to eleminate the possibility that something was getting f#$%ed up in the database by a faulty query somewhere in the big mess of code. (The upper layer was the "business logic" layer, which was the web or helper application.)
Then, I noticed that all of these database access objects were very similar: they all had access methods for each member of the class, which represented a single field in the database and had select/insert/update/delete routines.
I'd also developed a "dynamic object" at this point, where I'd have a huge variable-length field in the database which conatained many fields. This way I could change the object without worrying about compatibility in the back end database if I added/changed/removed fields. (We'll get back to this later.)
Beyond that, there were different ways of embedding objects (for example, a person object might have a phone number object embedded in it as part of an address-book application). (We'll get back to this later, too).
So there were different ways of logically grouping different sets of data, but the objects all shared a unified way of accessing the data. Thus was DBIx::Objects born - it provided a framework which would reallly guarantee that the objects would really function in a logically similar way - similar to the way that most GUI applications work in logically similar ways (they all have that File menu with Open , Save, Exit... The Help menu with Help topics, an optional upgrade, etc). So I guess you could call this library an API for developing database bound objects.
For more information, see http://www.beamartyr.net/YAPC/
BASIC OBJECTS API
The most basic type of object that can be used with this library simply get tied directly to fields in the database.
- blank($self, @args)
-
This is your constructor. Anything that is important for you to add to the object's new() method should be done here. DO NOT DECLARE YOUR OWN new() FUNCTION! This function gets a bless()ed $self passed as the first parameter, followed by the argument list to the new() call. The constructor is expected to call the internal _blank() function described below, and should call _primary(), if applicable.
In addition to being called by the constructor, this function is also called every time an empty (blank) instance of the object is needed.
A sample structure for the blank() method is included for reference:
sub blank { my $self=shift; $self->_register; $self->_blank("FOO", "BAR", ... , "LAST"); $self->_primary(1); # Optional - Marks as containing primary key }
- _refresh($self, [$package], $id)
-
This is called internally by refresh() and should contain code to sync the data structure with the back end database. Note that the $package variable is optional, but should be checked for (META: Remove code that makes this necessary). The subroutine should either refresh the data from the database and call _validate() or, if no suitable data is found, should call blank() [NOT _blank()]. In either case, it should return $self. A sample structure for the _refresh() method is included here for reference:
sub _refresh { my $self=shift; # Shift $self my $package=(UNIVERSAL::isa($_[0],__PACKAGE__) && shift) || ref($self); # Detect $package my $sth=$dbh->prepare_cached('SELECT FIRSTNAME, LASTNAME FROM PEOPLE WHERE (ID=?)'); # Set SQL $sth->execute(@_) or return $self->blank; # Run SQL or return blank() object if ($sth->rows!=1) { # A good SQL statement should always return EXACTLY one row $self->blank; # Bad SQL - return blank() } else { # Good SQL my $res=$sth->fetchrow_hashref; # Fetch results $self->{FIRSTNAME}=$res->{FIRSTNAME}; # Each element from the result set $self->{LASTNAME}=$res->{LASTNAME}; # gets passed to exactly one hash element $self->_validate; # And call _validate() to mark it as clean and in-sync with the DB } $sth->finish; # Finished with SQL return $self; # ...and return $self }
ADVANCED OBJECTS API
Beyond storing simple values, you can also magically construct objects using the primary key of the target objects. Using the above example, we spoke of a phone book catalog, which has a person object and a phone number object. Would it be nice, if instead of writing:
my $phone_number=Phone_Number->new($person->phone_number); print "Number is ".$phone_number->thenumber;
... you could simply write ...
print "Number is ".$person->phone_number->thenumber;
The advanced objects API lets you do just that, with almost no extra work on your behalf.
- _object($var, [$package])
-
This should be called in the blank() constructor. It is used to mark access method $var as an embedded object of type $package. If $package is not passed as an argument, it will default to the current package (eg, Your::Object). To use the feature, simply store the data you want passed to the object's constructor the same way you'd store any other data for a normal access method, and when you _validate the object, the data will be appropriately stored. The object will be constructed on the first call to the access method.
- _objarray($var, [$package])
-
This should be called in the blank() constructor. It is used to mark access method $var as an embedded array of objects of type $package. If $package is not passed as an argument, it will default to the current package (eg, Your::Object). The functionality is similar to that of _object except that we are dealing with arrays. As such, care must be taken to properly initialize the array. To use it, store an array (not a reference) in the _refresh function. When _validate is called on the object, the array will be stored and objects will be called on subsequent access via the method call $var. The method call will return the number of objects in the array if called in a scalar context, and the array of objects if called in a list context. The objects will be constructed upon access.
Note that this functionality is still under construction.
DBIx::Object::DBI
This object provides some shortucts for DBIx::Objects which use DBI as the backend datasource.
- _dbidbh
-
Gets/sets the DBI connection to use in the object. Use is as follows:
$dbh=new DBI($DSN); ... (in blank() ) $self->_dbidbh($dbh);
- _dbirefresh
-
Gets/sets the SQL statement to use in refresh() calls. Paramaters can be used, and will be set by the parameters actually passed to refresh() Remember that internally, DBIx::Objects assumes that it should receive valid data by calling
$self->refresh($self->id);
If that won't work for you, consider overloading the id() call, or implementing your own refresh() routine
INTERNAL FUNCTIONS
- _blank(@vars)
-
This should be called by the blank() constructor. The arguments should be all of the access methods provided by this class. It should *not* include inherited access methods, as they will automatically be discovered by AUTOLOAD. This will register all of the access methods in the registry under the module's namespace, so that AUTOLOAD can auto-load the module to refresh or update the database for it.
- _validate()
-
This method should be called from the _refresh function. It tells the object that its data has been updated and to remark itself as having fresh unchanged data.
AUTHOR AND COPYRIGHT
Copyright (c) 2003, 2004 Issac Goldstand <margol@beamartyr.net> - All rights reserved.
This library is free software. It can be redistributed and/or modified under the same terms as Perl itself.
SEE ALSO
8 POD Errors
The following errors were encountered while parsing the POD:
- Around line 447:
'=item' outside of any '=over'
- Around line 495:
You forgot a '=back' before '=head1'
- Around line 511:
'=item' outside of any '=over'
- Around line 536:
You forgot a '=back' before '=head1'
- Around line 541:
'=item' outside of any '=over'
- Around line 561:
You forgot a '=back' before '=head1'
- Around line 563:
'=item' outside of any '=over'
- Around line 576:
You forgot a '=back' before '=head1'