NAME
Object::Mediator - generic object persistence framework
SYNOPSIS
package Persistent;
use base qw( Object::Mediator );
__PACKAGE__->mk_attr ( qw(foo bar) );
sub _set_id {
my $self = shift;
my $id = generate_identity();
$self->identity( $id );
}
sub _insert {
my $self = shift;
$db_handle->insert ( $self->id, $self->foo, $self->bar );
}
sub _update {
my $self = shift;
$db_handle->update ( $self );
}
sub _delete {
my $self = shift;
$db_handle->delete ( $self->id );
}
sub _select {
my $self = shift;
my ( $foo, $bar ) = $db_handle->select ( $self->id );
$self->foo ( $foo );
$self->bar ( $bar );
}
DESCRIPTION
Object::Mediator attempts to be simple and fairly minimalistic object mapping framework. Main aims of development were: usage simplicity, end user transparency, database independency and minimization of database interaction with some kind of in-memory object state control system.
Database independency
Object::Mediator implements mapping by means of procedures described by you. So there are no limitations in using any DBMS/interface that you want to set for persistent storage for objects of your class.
End user transparency
Object::Mediator based classes are completely transparent to the end user. All operations with object persistent storage are performed implicitly.
Usage simplicity
The basic steps to make your objects persistent are:
1. Inherit from Object::Mediator,
2. Set up attributes to map with mk_attr() function,
3. Define identity and mapping procedures
There are five procedures you need to define in your module. All of them are object methods which called automatically, as a rule when object is destroyed or when the update() method is invoked manually. These procedures does not return anything.
Identity procedure definition
Object identity is a property of an object that distinguishes each object from all others. It's usually the same as the object identifier and must be an unique value.
- _set_id()
-
Generates object identity (probably uses database sequence for it) and invokes identity() method with newly obtained value. Called once when new object is created.
Mapping procedures definition
You should define the following procedures to explain Object::Mediator how to create, retrieve and update objects in database:
- _select()
-
Retrieves object from database and sets appropriate attributes.
- _insert()
-
Creates object in persistent storage.
- _delete()
-
Deletes object from persistent storage.
- _update()
-
Update database with object's current in-memory state.
After defining the procedures mentioned, you will be able to use your module and create persistent objects with it:
use Persistent; # your module
my $object = Persistent->new (
foo => 'bazooka'
);
$object->bar ( 'shotgun' );
Voila!
Minimization of database interaction
It seems obvious that there is no need to perform mapping every time object changes in memory. It has sense to invoke synchronization only if necessary and after work with the object is completed. Object::Mediator object state set is provided to implement this effective mapping. All objects stay in one of three states - NEW, MODIFIED or DELETED which determines (implies) corresponding procedure invocation when mapping is executed. There is also an UPDATED flag for all of those states to prevent recurring database calls. It is set by update() method after synchronization finished and testifies completeness of the object mapping. Here is a transition table:
| State
Event | N/U N/N D/U D/N M/U M/N
-------+-------+-------+-------+-------+-------+-------+
new() | N/N - N/N N/N N/N N/N
delete() | D/N D/U - - D/N D/N
set() | M/N - N/N M/N M/N -
State row enumerates possible object states. Event column lists actions/methods which affect on object's state. Note: as it will be described below the accessor methods (which are named same as attributes) are built up using Class::Accessor package, so all of them use set() method to perform object attribute value changes.
Furthermore, Object::Mediator supports uniqueness of objects in memory. In a given perl interpreter there will only be one instance of any given object at one time. This is implemented using a simple object lookup index with weak references for all alive objects in memory. It is not a traditional cache - when your objects go out of scope, they will be destroyed normally, and a future retrieve will instantiate an entirely new object. Refer to Scalar::Util::weaken function specification for details. The idea was inherited from Class::DBI module.
METHODS
Class methods
Following class methods are available:
mk_attr(@fields)
This creates accessor/mutator methods for each named field given in @fields using Class::Accessor module which is inherited by default. Functions mk_attributes() and mk_accessors() are aliases.
new(%attr)
Object constructor to create new object. Initial values for object attributes can be set thru %attr hash. _set_id() method is called implicitly within new() to set identity for newly created object.
retrieve($id)
Retrieves object by identity passed thru $id. Synonym: retr().
delete($id)
Deletes object by identity. Synonym: del().
object_autoupdate($on_or_off)
Sets default value for new object's autoupdate attribute. If off - update() method is not executed during DESTROY(). Can be changed for object individually using autoupdate() object method. Default value: on
purge_object_index_after()
Weak references are not removed from the index when an object goes out of scope. This means that over time the index will grow in memory. This is really only an issue for long-running environments like mod_perl, but every so often we go through and clean out dead references to prevent it. By default, this happens every 1000 object loads, but you can change that default for your class by calling the purge_object_index_every() method with a number.
Object methods
Following object methods are available:
identity()
Returns unique identifier of this object. Object identifier should be set by identity() only once, usually in _set_id(). Synonym: id().
delete()
Marks current object as deleted. Synonym: del().
update()
Performs appropriate mapping procedure for current object.
attr_modified()
Returns list of arguments which are modified.
set()
Overloaded Class::Accessor's set().
get()
Overloaded Class::Accessor's get().
AUTHOR
Eugen J. Sobchenko <esobchenko@gmail.com>
SEE ALSO
Class::DBI module is a perfect but more complex analogue for object-relational mapping from which lot of solutions were inherited.
COPYRIGHT
Copyright (c) 2004-2005 Eugen J. Sobchenko. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.