Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
SPOPS::Manual::ObjectRUser(Contributed Perl DocumSPOPS::Manual::ObjectRules(3)

NAME
       SPOPS::Manual::ObjectRules - Use	rules to give your object custom
       behavior

SYNOPSIS
       This document aims to answer the	questions:

       o   What	is a rule?

       o   What	can a rule do?

       o   What	is a ruleset?

       o   How do I implement a	rule?

DESCRIPTION
       When a SPOPS object calls "save()", "fetch()", or "remove()", the
       implementing class (e.g., SPOPS::DBI) takes care	of most	of the details
       for retrieving and constructing the object. However, sometimes you want
       to do something more complex or different. Each data manipulation
       method allows you to define two methods to accomplish these things. One
       is called before	the action is taken (usually at	the very beginning of
       the action) and the other after the action has been successfully
       completed.

       What kind of actions might you want to accomplish? Cascading deletes
       (when you delete	one object, delete a number of dependent objects as
       well); dependent	fetches	(when you fetch	one object, fetch all its
       component objects as well); implement a consistent data layer (such as
       full-text searching) by sending all inserts and updates to a separate
       module or daemon; data validation (by submitting	the data in the	object
       to a rules engine). Whatever -- it's up to you.

       Each of these actions is	a rule,	and together they are rulesets.

   Rule	Guidelines
       There are some fairly simple guidelines to rules:

       1.  Each	rule is	independent of every other rule. Why? Rules for	a
	   particular action may be executed in	an arbitrary order. You	cannot
	   guarantee that the rule from	one class will execute before the rule
	   from	a separate class.

       2.  A rule should not change the	data of	the object on which it
	   operates. Each rule should be operating on the same data. And since
	   guideline 1 states the rules	can be executed	in any order, changing
	   data	for use	in a separate rule would create	a dependency between
	   them.

	   NOTE: This item is up for debate

       3.  If a	rule fails, then the action is aborted.	This is	central	to how
	   the ruleset operates, since it allows inherited behaviors to	have a
	   say on whether a particular object is fetched, saved	or removed.

	   NOTE: This will probably be dropped in favor	of a more flexible
	   scheme that allows non-essential rules to fail without forcing the
	   entire action to fail.

   Rule	Uses
       Rules enable you	to implement a 'layer' over certain classes of data.
       Perhaps you want	to collect how many times users	from various groups
       visit a set of objects on your website. You can create a	fairly simple
       class that puts a rule into the ruleset of its children that creates a
       log entry every time a particular object	is fetch()ed. The class	could
       also contain methods for	dealing	with this information.

       This rule is entirely separate and independent from other rules,	and
       does not	interfere with the normal operation except to add information
       to a separate area of the database as the actions are happening.	In
       this manner, you	can think of them as a trigger as implemented in a
       relational database. However, triggers can (and often do) modify	the
       data of the row that is being manipulated, whereas a rule should	not.

   Rules and Aspects
       Another useful way to think of rules is in terms	of aspect oriented
       programming (AOP). AOP works in conjunction with	other methods of
       programming (object-oriented, procedural, functional) and allows	you to
       create joinpoints at which you perform actions with and on different
       types of	data.

       Read up more about AOP in the Aspect module, particularly
       Aspect::Intro.

RULESET	HOOKS
       pre_fetch_action({ id =>	$ })

       Called before a fetch is	done, although if an object is retrieved from
       the cache this action is	skipped. (NOTE:	THIS MIGHT NOT BE TRUE -- WE
       NEED TO IMPLEMENT CACHING AND SEE HOW THIS WORKS	IN REALITY.) The only
       argument	is the ID of the object	you are	trying to fetch.

       This hook is generally not used very often.

       post_fetch_action( \% )

       Called after a fetch has	been successfully completed, including after a
       positive	cache hit.

       pre_save_action({ is_add	=> bool	})

       Called before a save has	been attempted.	If this	is an add operation
       (versus an update), we pass in a	true value for the 'is_add' parameter.

       post_save_action({ is_add => bool })

       Called after a save has been successfully completed. If this object was
       just added to the data store, we	pass in	a true value for the 'is_add'
       parameter.

       pre_remove_action( \% )

       Called before a remove has been attempted.

       post_remove_action( \% )

       Called after a remove has been successfully completed.

RULE IMPLEMENTATION
       Adding rules to an object class is very simple. You have	one simple
       method to create	to add your rule(s) to the ruleset for an object, and
       then the	actual rules.

   Rule	Factory
       ruleset_factory(	$class,	\%class_ruleset	)

       Interface for adding rules to a class. The first	argument is the	class
       to which	we want	to add the ruleset, the	second is the ruleset for the
       class. The ruleset is simply a hash reference with keys as the methods
       named above ('pre_fetch_action',	etc.) pointing to an arrayref of code
       references.

       This means that every phase named above above ('pre_fetch_action',
       etc.) can run more than one rule. Here is an example of what such a
       method might look like -- this one is taken from	a class	that
       implements full-text indexing. When the object is saved successfully,
       we want to submit the object contents to	our indexing routine. When the
       object has been removed successfully, we	want to	remove the object from
       our index:

	 sub ruleset_factory {
	   my (	$class,	$rs_table ) = @_;
	   my $obj_class = ref $class || $class;
	   push	@{ $rs_table->{post_save_action} }, \&reindex_object;
	   push	@{ $rs_table->{post_remove_action} }, \&remove_object_from_index;
	   return __PACKAGE__;
	 }

       Note that the return value is always the	package	that inserted the
       rule(s) into the	ruleset. This enables the module that creates the
       class (SPOPS::Configure::Ruleset) to ensure that	the same rule does not
       get entered multiple times.

       POSSIBLE	CHANGES

       Instead of the above, we	may change to something	like:

	 sub ruleset_factory {
	   my (	$class ) = @_;
	   return { post_save_action   => \&reindex_object,
		    post_remove_action => \&remove_object_from_index };
	 }

       This is simpler,	easier to follow and more consistent with how we
       discover	behaviors to execute during the	code generation	process.

   Rule	Processor
       You should never	have to	worry about this since it is implemented in
       SPOPS and therefore part	of every SPOPS class. But it is	here for
       completeness:

       ruleset_process_action( ($object|$class), $action, \%params )

       This method executes all	the rules in a given ruleset for a given
       action. For instance, when called with the action name
       'pre_fetch_action' it executes all the rules in that part of the
       ruleset.

       Return value is true if all the rules executed ok, false	if not.

       NOTE: THIS MAY BE MODIFIED SO THAT EACH RULE CAN	REPORT A STATUS	WHICH
       IS AVAILABLE FOR	LATER INSPECTION.

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

       See SPOPS::Manual for license.

AUTHORS
       Chris Winters <chris@cwinters.com>

perl v5.32.1			  2004-06-02	 SPOPS::Manual::ObjectRules(3)

NAME | SYNOPSIS | DESCRIPTION | RULESET HOOKS | RULE IMPLEMENTATION | COPYRIGHT | AUTHORS

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=SPOPS::Manual::ObjectRules&sektion=3&manpath=FreeBSD+13.1-RELEASE+and+Ports>

home | help