NAME

SPOPS::Manual::Serialization - How SPOPS serializes objects

SYNOPSIS

This part of the SPOPS manual aims to answer the following questions:

  • How does serialization work?

  • How can I customize serialization?

  • How does caching work?

  • How can I lazy-load my fields?

DESCRIPTION

CUSTOMIZING SERIALIZATION

Pre/Post Hooks

SPOPS allows you to create multiple pre- and post-actions to save(), fetch() and remove(). These actions can be as simple or complex as you like and allow objects to be extremely flexible.

These the actions implemented in the hooks are called rules, and each collection of rules is called a ruleset. Rulesets are documented in SPOPS::Manual::ObjectRules.

Failed Actions

If an action fails, the 'fail' method associated with that action is triggered. This can be a notification to an administrator, or saving the data in the filesystem after a failed save.

fail_fetch()

Called after a fetch has been unsuccessful.

fail_save()

Called after a save has been unsuccessful.

fail_remove()

Called after a remove has been unsuccessful.

CACHING

SPOPS has hooks for object caching. You will need to return a caching object via the a global_cache() method implemented either in your SPOPS object class one of its parents.

The caching object will have a simple interface so it's easy to wrap it around your favorite caching backend. (Who wants to write this stuff from scratch themselves?)

pre_cache_fetch()

Called before an item is fetched from the cache; if this is called, we know that the object is in the cache, we just have not retrieved it yet.

post_cache_fetch()

Called after an item is successfully retrieved from the cache.

pre_cache_save()

Called before an object has been cached.

post_cache_save()

Called after an object has been cached.

pre_cache_remove()

Called before an object is removed from the cache.

post_cache_remove()

Called after an object is successfully removed from the cache.

LAZY LOADING

This section describes how to implement lazy loading for your objects.

Every implementation should be able to handle the following column groups that should always be available:

  • _id_field: Column group containing only the ID field. This can be useful if you are cycling through large groups of objects only for their ID value. (For instance, to set security values for many objects at once.)

What You Need To Do

Here are the methods you need to create to implement lazy loading:

get_lazy_load_sub()

Called by SPOPS when initializing a new object if one or more 'column_group' entries are found in the configuration. It should return a coderef that implements lazy loading for a single field. (See below.)

perform_lazy_load( $class, \%data, $field )

Interface for a subclass to implement lazy loading. The method get_lazy_load_sub() should return a coderef conforming to this interface.

The implementation should return the value for $field given the object information \%data, which is a map of fieldname to value and includes the ID field and value of the object.

For lazy loading usage, see SPOPS::Manual::Object.

What SPOPS does

These are methods implemented by SPOPS for lazy loading.

is_loaded( $field )

Returns true if $field has been loaded, false if not.

set_loaded( $field )

Sets the 'loaded' property of $field to true.

clear_loaded( $field )

Sets the 'loaded' property of $field to false.

set_all_loaded()

Sets the 'loaded' property of all fields in the object to true.

clear_all_loaded()

Sets the 'loaded' property of all fields in the object to false.

For an example of how a SPOPS subclass implements lazy-loading, see SPOPS::DBI.

STORABLE SERIALIZATION

The main SPOPS class from which all SPOPS objects derive has the methods store(), nstore(), retrieve() and fd_retrieve() acting as delegates for methods of the same name in Storable. (We can add more as needed.)

Example:

 1:  # Fetch the user object and if retrieved, store it in the session
 2: 
 3:  my $session = $session_class->create;
 4:  my $login_name = read_login_name();
 5:  my $user = eval { $user_class->fetch_by_login_name( $login_name ) };
 6:  if ( $@ ) { ... }
 7:  $session->{user_object} = $user->store;
 8: 
 9:  # ... time passes ...
10: 
11:  my $session = $session_class->fetch( $session_id );
12:  my ( $user );
13:  if ( $session->{user_object} ) {
14:     $user = $user_class->retrieve( $session->{user_object} );
15:  }
16:  else {
17:      my $login_name = read_login_name();
18:      my $user = eval { $user_class->fetch_by_login_name( $login_name ) };
19:      ...
20:  }

This has not been extensively tested, particularly with the nstore() option for transporting objects among different architectures. In theory, this shouldn't be an issue at all, as long as when thawing the object the specific SPOPS class has been previously initialized.

This could be an interesting area of future development, since you could in theory send an object over a network along with a minimal configuration and object definition that, when it reached the read_code section of the code generation, reached out over the network to read in the actual meat of a class. Basically, the thawing routine could check to see if it had processed the SPOPS class and if not, grab it off the network and whip it up.

COPYRIGHT

Copyright (c) 2001-2004 Chris Winters. All rights reserved.

See SPOPS::Manual for license.

AUTHORS

Chris Winters <chris@cwinters.com>