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

NAME

SPOPS::Manual::Configuration - Description of variables used in the SPOPS configuration process

SYNOPSIS

This document aims to answer the questions:

  • How do I setup logging?

  • What configuration options are available for SPOPS objects?

  • How do I modify configuration options?

  • How can I get to the configuration items once the object class is operational?

  • How can I add new configuration items?

LOGGING

Using Log4perl

As of version 0.81 SPOPS now uses Log::Log4perl to issue logging messages. This is a far, far better system than the fragile and just plain busted system used previously.

The log4perl documentation is excellent and if you're really interested I strongly recommend you read it. However...

Quick Guide

SPOPS comes with a sample configuration file for log4perl. It's found in the root of the source distribution and looks like this:

 ########################################
 # ROOT CATEGORY
 
 # Log to a file 'spops.log' (controlled below)
 #log4perl.logger = DEBUG, FileAppender
 
 # Log to STDERR -- this is the default to replicate earlier behavior
 log4perl.logger = DEBUG, ScreenAppender
 
 ########################################
 # CATEGORIES
 
 log4perl.logger.SPOPS              = INFO
 log4perl.logger.SPOPS.DBI          = INFO
 log4perl.logger.SPOPS.SQLInterface = WARN
 log4perl.logger.SPOPS.ClassFactory = WARN
 
 ########################################
 # APPENDERS
 
 # Normal file log - to use this just specify 'FileAppender' as the root category
 
 log4perl.appender.FileAppender          = Log::Log4perl::Appender::File
 log4perl.appender.FileAppender.filename = spops.log
 log4perl.appender.FileAppender.layout   = Log::Log4perl::Layout::PatternLayout
 log4perl.appender.FileAppender.layout.ConversionPattern = %d{HH:mm:ss} %p %c %C (%L) %m %n
 
 # Normal STDERR log
 
 log4perl.appender.ScreenAppender          = Log::Log4perl::Appender::Screen
 log4perl.appender.ScreenAppender.stderr   = 1
 log4perl.appender.ScreenAppender.layout   = Log::Log4perl::Layout::PatternLayout
 log4perl.appender.ScreenAppender.layout.ConversionPattern = %d{HH:mm:ss} %p %c %C (%L) %m %n
 

To initialize log4perl just add the following to your script, or put it in a common place and call it at your script startup:

 use Log::Log4perl;
 
 # 'log4perl.conf' is the name of your configuration file
 
 Log::Log4perl::init( 'log4perl.conf' );

Easy! The default configuration file issues statements to STDERR, just like the old debugging statements from SPOPS. But you can also issue them to a file, log them to a database, send them to syslog or whatever you like. You can even log the messages from important modules (e.g., 'SPOPS::DBI' and 'SPOPS::SQLInterface') to separate files to make it easier to separate the wheat from the chaff.

DESCRIPTION

These are variables used in all SPOPS implementations. The name of the variable is the key used in the configuration hashref.

Here is a fairly minimal example of a configuration hashref:

  1: my $spops = {
  2:   'news' => {
  3:      class           => 'My::News',
  4:      isa             => [ qw/ MyApp::Datasource SPOPS::DBI::Pg SPOPS::DBI / ],
  5:      rules_from      => [ 'My::DiscoverField' ],
  6:      code_class      => [],
  7:      field_discover  => 'yes',
  8:      base_table      => 'news',
  9:      id_field        => 'news_id',
 10:      increment_field => 1,
 11:      no_insert       => [ 'news_id' ],
 12:      no_update       => [ 'news_id' ],
 13:   },
 14: };

General Configuration Fields

class ($)

The name of the class SPOPS will build.

code_class (\@) (optional)

An arrayref of class names that will be read in as additional behaviors to the SPOPS-generated class.

field (\@) (optional if setting dynamically)

An arrayref of fieldnames used in this object; the case of these may be modified to be all lowercase.

field_raw (\@) (optional)

An arrayref of fieldnames used in this object in their original cases.

strict_field (bool) (optional)

A flag indicating whether to use strict field checking.

isa (\@)

An arrayref of classes representing the ISA parent hierarchy of the generated class. These classes are examined for class factory behaviors and object rules during the code generating process, and they're also used in the normal ISA fashion as class ancestors.

rules_from (\@) (optional)

An arrayref of classes to read class factory behaviors and object rules from. These classes are not used as ancestors of the class, and once the code generation process is done the generated class has nothing to do with them.

id_field ($ or \@)

The name of the field used as the ID (or primary key) field for the object. Currently, multi-field primary keys are supported but only in SPOPS::DBI. (See SPOPS::Manual::Object for more information about multi-field primary keys.) Multi-field primary keys use an arrayref rather than a string, and the order of the fields must be the same at all times.

column_group (\%) (optional)

Used by the lazy loading process to determine the group-to-fieldname mappings. See SPOPS::Manual::Object for more information on lazy loading.

field_map (\%) (optional)

A hashref of field-to-field relationships so you can make an object appear as another one. For instance, if you have a legacy datastore with short, unreadable fieldnames you can make it appear as a modern, intelligible object. See SPOPS::Manual::Object for more information on field mapping.

default_values (\%) (optional)

Hashref of field names and default values for the fields when the object is initialized with new().

Normally the values of the hashref are the defaults to which you want to set the fields. However, there are two special cases of values:

'NOW' This string will insert the current timestamp in the format yyyy-mm-dd hh:mm:ss.

\% A hashref with the keys 'class' and 'method' will get executed as a class method and be passed the name of the field for which we want a default. The method should return the default value for this field.

One problem with setting default values in your object configuration and in your database is that the two may become unsynchronized, resulting in many pulled hairs when debugging.

To get around the synchronization issue, you can set this dynamically using various methods with SPOPS::ClassFactory. (A sample, My::DBI::FindDefaults, is shipped with SPOPS.)

multivalue (\@) (optional)

List all fieldnames that can hold multiple values. Currently the only native support for this is in SPOPS::LDAP, but you can also use it along with some object rules to fake relationships.

no_insert (\@) (optional)

List of fields not to use when creating a new object in the datastore.

no_update (\@) (optional)

List of fields not to update when saving a previously saved object.

skip_undef (\@) (optional)

You can elect not to include a field that's undefined when saving or updating an object by including it in this list.

creation_security (\%) (required if you're using security)

If you're using security, specify here what security the object will have when it's first created.

no_security (bool) (optional)

If true, the object won't use security even if SPOPS::Secure is in the isa.

no_cache (bool) (optional)

If true, the object won't be cached even if the application specifies that it should. (Currently unused.)

object_name ($)

The general name of a type of object. For an object representing a news story this might be 'News'.

name ($)

How an object is uniquely identified to humans. This is often used when displaying an object of unknown origin -- we can ask about its information using the object_description() method that all SPOPS objects have. For an object representing a news story this might be 'title'.

The scalar can specify either a property (e.g., a field name 'title' for a news story) or a method on the object (e.g., a method 'full_name' which puts together a person's name smartly). If the specified method isn't found the title in object_description() is left undefined.

NOTE: Since we allow you to specify a method name the coderef option (previously found in these docs) is no longer necessary. As a result it is being phased out and will probably be eliminated before we reach 1.0. (Whenever that is...)

display (\%)

A URL specifying how to display an instance of an object. The object_description() method uses a base URL then appends relevant query information to it.

as_string_order (\@) (optional)

Ordered list of object fields to use when the as_string() method is called. If you don't specify this SPOPS will use the object fields as listed in the field configuration key.

as_string_label (\%) (optional)

Hashref of object field-to-label mappings used when the as_string() method is called.

has_a (\%) (optional)

Metadata for SPOPS to use when building a relationship from one object to another. This generally means that the object itself has the information in its own properties necessary to fetch one or more objects.

Here is a list of possible formats and what results from them:

  1: # Given:
  2: 'contained' => {
  3:    class => 'My::ContainedClass',
  4:    id    => 'contained_id',
  5: }
  6: 
  7: # Basic usage
  8:    has_a => { class-name => 'id-field' },
  9:    has_a => { My::ContainedClass => 'contained_id' }
 10:    -- Creates method 'contained'
 11: 
 12: # Other ID field name
 13:    has_a => { class-name => 'id-field' },
 14:    has_a => { My::ContainedClass => 'original' }
 15:    -- Creates method 'original_contained'
 16: 
 17: # Multiple ID fields
 18:    has_a => { class-name => [ 'id-field', 'id-field' ] },
 19:    has_a => { My::ContainedClass => [ 'contained_id, 'original' ] }
 20:    -- Creates methods 'contained' and 'original_contained'
 21: 
 22: # Specific method to create and a default 
 23:    has_a => { class-name => { method-name => 'id-field' }, 'id-field' },
 24:    has_a => { My::ContainedClass =>
 25:                     { 'originally_contained_by' => 'original' },
 26:                     'contained_id' },
 27:    -- Creates methods 'originally_contained_by' and 'contained'
 28: 
 29: # Specific method to create and multiple other ID fields
 30:    has_a => { class-name => { method-name => 'id_field'},
 31:                             [ 'id-field', 'id-field' ]    },
 32:    has_a => { My::ContainedClass =>
 33:                     { 'originally_contained_by' => 'original' },
 34:                     [ 'contained_id', 'future' ] }
 35:    -- Creates methods 'originally_contained_by', 'contained' and
 36:       'future_contained'

See SPOPS::Manual::Relationships for more information on how this works.

fetch_by (\@) (optional)

A list of fields that tell SPOPS you want to create special methods for retrieving objects based on a the value of particular field. For instance, with user objects we might want to specify 'email' and 'login_name' so SPOPS will create the methods 'fetch_by_email' and 'fetch_by_login_name'.

# TODO: Add more here.

SPOPS::DBI CONFIGURATION

This section describes configuration keys that are used differently by SPOPS::DBI than the default, as well as new configuration keys used only by SPOPS::DBI.

General Configuration Fields

isa (\@)

Same as a normal SPOPS field, but it must have SPOPS::DBI in it.

base_table ($)

Table name for data to be stored. This may be modified during the configuration process to be a fully qualified name (e.g., 'user.table') where necessary. The value is always available via the table_name() class method.

sql_defaults (\@) (optional)

List of fields that have defaults defined in the SQL table. For instance:

   active   CHAR(3) DEFAULT 'yes',

After SPOPS::DBI fetches a record, it then checks to see if there are any defaults for the record and if so it refetches the object to ensure that the data in the object and the data in the database are synced.

field_alter (\%) (optional)

Allows you to define different formatting behaviors for retrieving fields. For instance, if you want dates formatted in a certain manner by the database rather than after the fact, you can do something like:

 field_alter => {
    posted_on => q/DATE_FORMAT( posted_on, '%M %e, %Y (%h:%i %p)' )/,
 }

Which instead of the default time format:

 2000-09-26 10:29:00

will if you're using MySQL return something like:

 September 26, 2000 (10:29 AM)

These are typically database-specific.

insert_alter (\%) (optional)

Allows you to define different formatting behaviors for the values of inserted fields. The field is the key, the value is a sprintf format that should contain one %s sequence into which the actual value of the object will be plugged.

For instance, your database may use a non-standard format for inserting dates. You can specify:

 insert_alter => {
    last_login => "to_date('%s','YYYY-MM-DD HH24:MI:SS')"
 }

So when the object value is set:

 $object->{last_login} = '2002-04-22 14:47:32';

What actually gets put into the database is:

 INSERT INTO table
 ( ... last_login ... )
 VALUES 
 ( ... to_date( '2002-04-22 14:47:32', 'YYYY-MM-DD HH24:MI:SS' ) ... )

Note that the resulting value is passed unquoted to the database. Also note that the configured field name must be in lower-case, even if the field in the database is in mixed- or upper-case.

You can override a SPOPS::DBI method If you need more complicated processing than this allows, see the docs for details.

General Relationship Fields

links_to (\%) (optional)

The 'links_to' field allows you to specify a SPOPS class and specify which table is used to link two objects. Note that this relationship assumes a link table that joins two separate tables. When you sever a link between two objects, you are only deleting the link rather than deleting an object.

Here is a list of possible formats and what results from them:

  1: # Given:
  2: 'contained' => {
  3:    class => 'My::ContainedClass',
  4:    id    => 'contained_id',
  5: }
  6: 
  7: # Basic usage
  8:    links_to => { class-name => 'linking-table-name' }
  9:    links_to => { My::ContainedClass => 'contained_link' }
 10:    -- Creates method 'contained', 'contained_add' and 'contained_remove'

See SPOPS::Manual::Relationships for more information on how this works.

SPOPS::LDAP CONFIGURATION

Configuration of an SPOPS::LDAP data object is similar to that of other SPOPS objects, with a few modifications.

General Configuration Fields

isa (\@)

Same as a normal SPOPS field, but it must have SPOPS::LDAP in it.

base_dn ($)

DN in an LDAP tree where this object is located. For instance, the common 'inetOrgPerson' type of object might be located under:

  base_dn  => 'ou=People,dc=MyCompany,dc=com'

While 'printer' objects might be located under:

  base_dn  => 'ou=Equipment,dc=MyCompany,dc=com'

Note that SPOPS::LDAP::MultiDatasource allows you to specify a partial DN on a per-datasource basis.

ldap_object_class (\@)

When you create a new object you can specify the LDAP object class yourself when creating the object or SPOPS::LDAP can do it for you behind the scenes. If you specify one or more LDAP object class strings here they will be used whenever you create a new object and save it.

Example:

 ldap_object_class => [ 'top', 'person', 'inetOrgPerson',
                        'organizationalPerson' ]

ldap_fetch_object_class ($) (optional)

Specify an objectclass here to ensure your results are restricted properly. This is also used to do an 'empty' search and find all records of a particular class.

NOTE: This is only used with the fetch_group() and fetch_iterator() methods.

Example:

 ldap_fetch_object_class => 'person'

ldap_update_only_changed (bool) (optional)

Set a true value here to update only those fields whose values have changed.

multivalue (\@) (optional)

You must list the fields here that may have multiple values in the directory. Otherwise the object will have only one of the values and, on saving the object, will probably wipe out all the others.

Example:

 multivalue  => [ 'objectclass', 'cn' ]

id_value_field ($) (optional)

Returns the field used for the ID value (a string) in this object. By default this is the value stored in 'id_field', but there are cases where you may wish to use a particular fieldname for the DN of an object and the value from another field.

Relationship Fields

The 'has_a' relationship exists where one object has the information for one or more objects of another type in its own properties. The DN(s) for the other object(s) are held in one of the object properties.

For instance, one of the objects represented in the standard LDAP schema is a group. This has the object class 'groupOfUniqueNames' and a property 'uniquemember' which may have zero, one or more DNs for member objects.

The 'links_to' relationship exists where one object is related to one or more objects of another type, but the information is held in the property of the other object. So a member of one or more groups would use a 'links_to' relationship to find all the groups to which the member belongs.

As an example of both of these, take the canonical relationship of users to groups. The group object 'has_a' zero or more user objects since it is a 'groupOfUniqueNames' and has the property 'uniquemember'. So we would define it:

 group => {
    class    => 'My::Group',
    isa      => [ 'SPOPS::LDAP' ],
    has_a    => { 'My::User' => 'uniquemember' },
 },

So a group that had the following DNs in its 'uniquemember' field:

  cn=Fred Flintstone,ou=People,dc=hanna-barberra,dc=com
  cn=Wilma Flintstone,ou=People,dc=hanna-barberra,dc=com
  cn=Dino,ou=People,dc=hanna-barberra,dc=com

would return user objects for Fred, Wilma and Dino.

The user object might be defined:

 user => {
    class    => 'My::User',
    isa      => [ 'SPOPS::LDAP' ],
    links_to => { 'My::Group' => 'uniquemember' },
 },

And would find all groups that had its DN in the field 'uniquemember' of the group objects.

This is generally more straightforward than the DBI equivalent.

SPOPS::LDAP::MultiDatasource Configuration

Also see the SPOPS::LDAP configuration information unless otherwise noted.

General Configuration Fields

datasource (\@)

If you want to use multiple datasources, you need to specify them. The datasource key holds an arrayref of datasources in the order you want them searched.

Example:

 my $spops = {
   class      => 'My::Person',
   isa        => [ 'SPOPS::LDAP::MultiDatasource' ],
   datasource => [ 'main', 'accounting', 'development', 'etc' ],
 };

The 'etc' datasource will be the last one searched. This would obviously be a performance hit if most of your objects were there.

ldap_base_dn ($ or \%)

First, this should not be a full DN, but rather a partial one that when matched up with a datasource creates a full DN. For example:

 my $spops = {
   class        => 'My::Person',
   isa          => [ 'SPOPS::LDAP::MultiDatasource' ],
   ldap_base_dn => 'ou=People',
 };

Second, if you use a scalar for this key you are in effect saying 'use the same partial DN for all my datasources'. But if you are using different partial DNs for different datasources, you need to specify them:

 my $spops = {
   class        => 'My::Person',
   isa          => [ 'SPOPS::LDAP::MultiDatasource' ],
   datasource   => [ 'main', 'accounting', 'development', 'etc' ],
   ldap_base_dn => { main        => 'ou=People',
                     accounting  => 'ou=BeanCounters',
                     development => 'ou=Geeks',
                     etc         => 'ou=Commoners' },
 };

COPYRIGHT

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

See SPOPS::Manual for license.

AUTHORS

Chris Winters <chris@cwinters.com>