The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Object::Mediator - generic object persistence framework

SYNOPSIS

package Persistent;

use base qw( Object::Mediator );

__PACKAGE__->mk_attr ( foo bar baz );

sub _set_id {
	my $self = shift;

	$self->generate_identity();
}

sub _insert {
	my $self = shift;

	$self->insert_in_database();
}

sub _update {
	my $self = shift;

	$self->update_in_database();
}

sub _delete {
	my $self = shift;

	$self->delete_from_database();
}

sub _select {
	my $self = shift;

	$self->select_from_database();
}

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.

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. Describe mapping procedures

There are five mapping 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. Here is details below:

_set_id()

Sets object identity. Called once when new object is created.

_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.

Now you will able to use your module and create persistent objects:

use Persistent; # your module

my $object = Persistent->new (
	foo => 'bazooka',
	bar => 'uzi',
);

$object->baz ( 'shotgun' );

Voila!

End user transparency

Object::Mediator based classes are completely transparent to the end user. All operations with object persistent storage are performed implicitly.

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.

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 invokation when mapping is executed. There is also UPDATED flag for all of those states to prevent recurring database calls. It sets 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 descibed 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 live 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.

delete($id)

Deletes object by identity.

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 idividually 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 evey 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.

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

Currently working on some-kind of homepage for this module.

Class::DBI is a perfect 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.