The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Backed_Objects - Create static files from a database.

VERSION

Version 1.16

SYNOPSIS

Create static files from a database. Update the files every time when you update the database.

It can be used with any kind of database, for example SQL databases, Berkeley databases, data stored in .ini files, etc.

USAGE OF THE CLASS

The class Backed_Objects is an abstract base class and you need to derive your class from it. For further suppose you developed a class HTML_DB derived from Backed_Objects. We will call HTML (for example) files which are updated by this module the view.

All methods can be called either as object methods or as class methods.

Calling these as class methods may be convienient when you do not need to specify additional parameters to be put into an object.

Thus the following alternatives are possible:

  HTML_DB->output_all_and_order;

or

  my $obj = HTML_DB->new;
  $obj->output_all_and_order;

Examples below assume that you are familiar with SQL and DBI module.

Database update methods

The class Backed_Objects offers you flexibility on the way how you update your database.

One variant is to override do_insert, do_update, do_delete, post_process methods, so that they will update your database when insert, update, delete methods are called.

The other variant is to update the database yourself and afterward to call insert, update, delete which will call the default do-nothing do_insert, do_update, do_delete, post_process methods.

The object and the ID

A database stores objects, every object stored in a database has an ID. An object may be without an ID when it is not yet stored into the DB, but you must assign an ID to an object when you store it in the DB, either by overriding do_insert method which should set the object ID or yourself in your own code (without overriding do_insert). HTML_DB must have id method which receives an object and return its ID.

The interface of this module does not specify what objects are. Objects may be hashes or any other data structures.

Every object inserted into the database has ID (which may be a natural number, but is not required to be a number).

Sometimes you may want the objects and IDs to be the same. For example, it is often OK for an object and an ID to be a row ID in a SQL database. Or you may want an object to be a hash representing a row in an SQL DB.

Sometimes a middle solution is fit: Store an object as a hash with some values from the database and read the rest values from the DB when needed, using the ID stored in the object.

An other possibililty for an object is to be a hash based on user input in a HTML form.

METHODS

id

This abstract (not defined in Backed_Objects method) must be defined to return the ID of an object.

Examples:

  sub id {
    my ($self, $obj) = @_;
    return $obj->{id};
  }

or

  # Objects are simple IDs
  sub id {
    my ($self, $obj) = @_;
    return $obj;
  }

all_ids

This abstract (not defined in Backed_Objects method) must return a list of all IDs in the database.

  sub all_ids {
    my ($self) = @_;
    return @{ $dbh->selectcol_arrayref("SELECT id FROM table") };
  }

do_select

This abstract method should return an object from the DB having a given ID.

  sub do_select {
    my ($self, $id) = @_;
    return $dbh->selectrow_hashref("SELECT * FROM table WHERE id=?", undef, $id);
  }

or

  # Objects are simple IDs
  sub do_select {
    my ($self, $id) = @_;
    return $id;
  }

select

This method returns an object from the DB or undef if the ID is absent (undefined or zero).

See its implementation:

  sub select {
    my ($self, $id) = @_;
    return undef unless $id;
    return $self->do_select($id);
  }

do_insert, do_update, do_delete, post_process

By default these methods do nothing. (In this case you need to update database yourself, before calling insert, update, or delete methods.)

You may override these methods to do database updates:

  sub do_insert {
    my ($self, $obj) = @_;
    my @keys = keys %$obj;
    my @values = values %$obj;
    my $set = join ', ', map { "$_=?" } @keys;
    $dbh->do("INSERT table SET $set", undef, @values);
    $obj->{id} = $dbh->last_insert_id(undef, undef, undef, undef);
  }

  sub do_update {
    my ($self, $obj) = @_;
    my @keys = keys %$obj;
    my @values = values %$obj;
    my $set = join ', ', map { "$_=?" } @keys;
    $dbh->do("UPDATE table SET $set WHERE id=?", undef, @values, $obj->{id});
  }

  sub do_delete {
    my ($self, $id) = @_;
    $dbh->do("DELETE FROM table WHERE id=?", undef, $id);
  }

  sub post_process {
    my ($self, $obj) = @_;
    ...
  }

do_insert should set object ID after it is saved into the database.

post_process is called by insert after the object is inserted into the database (and the object ID is set). It can be used for amending the object with operations which require some object ID, for example for uploading files into a folder with name being based on the ID.

post_process is also called by update.

outputter

This method should return a value used to output a view of the DB (for example it may be used to output HTML files and be a hash whose values are HTML templates).

Example:

  use File::Slurp;

  sub outputter {
    my ($self) = @_;
    my $template_dir = "$ENV{DOCUMENT_ROOT}/templates";
    return { main_tmpl => read_file("$template_dir/main.html"),
             announce_tmpl => read_file("$template_dir/announce.html") };
  }

The default implementation returns undef.

insert, update, delete

  HTML_DB->insert($obj);
  HTML_DB->update($obj);
  HTML_DB->delete($id);

These functions update the view based on the value $obj from the DB. They are to be called when an object is inserted, updated, or deleted in the DB.

If you've overridden the do_insert, do_update, or do_delete methods, then insert, update, or delete methods update the database before updating the view.

Note that insert methods calls both on_update and on_insert methods (as well as some other methods, see the source).

insert and update also call post_process.

update also calls before_update before calling do_update. The before_update method can be used to update the data based on old data in the DB, before the DB is updated by do_update.

on_update, on_update_one

on_update method it called when an object in the database is updated or after a new object is inserted.

on_update_one is the method called by on_update. The on_update_one method is meant to update view of one object. Contrary to this, on_update may be overridden to update several objects by calling on_update_one several times. For example, when updating title of a HTML file, we may want to update two more HTML files with titles of prev/next links dependent on the title of this object.

By default on_update_one calls the output method to update the view of the object.

on_insert, on_delete, on_order_change, before_update

  sub on_insert {
    my ($self, $obj) = @_;
    ...
  }

  sub on_delete {
    my ($self, $id) = @_;
    ...
  }

  sub on_order_change {
    my ($self) = @_;
    ...
  }

  sub before_update {
    my ($self, $obj) = @_;
    ...
  }

These methods (doing nothing by default) are called correspondingly when:

inserting a new object into the database;
deleting an object from the database;
changing order of objects in the database (including the case of inserting a new object).
before calling do_update to update the database.

By default these methods do nothing.

You may update your view in your overrides of these methods.

before_update is called by update (but not by insert) before updating the DB with do_update.

on_any_change

  sub on_any_change {
    my ($self) = @_;
    ...
  }

This method is called after every change of the database, for example, after insertion, deletion, update, etc.

do_output

  sub do_output {
    my ($self, $outputter, $obj, $update) = @_;
    ...
  }

This is the main method to output your files (the view).

It receives the object and the outputter returned by the outputter method.

$update is TRUE only if it is called from update method. It can be used not to update what needs not updating. (TODO: Document it better.)

order_change

  HTML_DB->order_change;

Call order_change after you changed the order of objects in the database (but not after calling insert or delete method which call order_change automatically).

output_by_id

An internal function.

output_all

  HTML_DB->output_all;
  HTML_DB->output_all_and_order;

output_all updates the entire set of your files based on the data in the DB.

output_all_and_order additionally updates data dependent on the order of objects in the DB.

Use these methods to update your all files (for example, after your template changed).

save

  HTML_DB->save($obj);

This saves an object into the DB: updates it if it is already in the DB (has an ID) or inserts it into the DB if it has an undefined ID.

The actual code:

  sub save {
    my ($self, $obj) = @_;
    if($self->id($obj)) {
      $self->update($obj);
    } else {
      $self->insert($obj);
    }
  }

output

An internal function.

AUTHOR

Victor Porton, <porton@narod.ru>

BUGS

Please report any bugs or feature requests to bug-backed_objects at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Backed_Objects. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

In the current version of Backed_Objects there are no provision for passing file handles for example got from a HTML form with a file control. A complexity is that usually to upload a file we need to already know the ID of a row in a database what is possible only after inserting into the DB. Your suggestions how to deal with this problem are welcome.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Backed_Objects

You can also look for information at:

LICENSE AND COPYRIGHT

Copyright 2011 Victor Porton.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.