Understanding the Main Class Functions
--------------------------------------
The following document identifies the main functions that are called (and in which order that they are called
in) for objects that are derived from the standard "class_base" base class (i.e. all Meta "Class" objects).
It should be noted that the "validate" function actually gets called twice (the first call occurs immediately
after the "to_store" call and the second call occurs immediately after the "for_store" call). The second call
is not explicitly documented below as this secondary validation is only intended as a failsafe mechanism (for
unexpected bad code in "for_store").
-------------------------------------------------------------------------------------------------------------
1) Creating a new record:
Protocol: perform_create <uid> <dtm> <module> <mclass> <key> field1=value1,field2=value2...
(where <key> is " " for an automatically created key and for clone "[<new_key>] <clone_key>")
Equivalent C++ Code for Rules:
object.op_create( <key> );
object.<field1>( <value1> );
object.<field2>( <value2> );
...
object.op_apply( );
Function Lock Before Lock After Description
-------------------------------------------------------------------------------------------------------------
(op_create - <key> [<clone_key>])
at_create Create Create Record is in an "empty" or cloned state. This function is available
to provide different default field values, although it is generally
only used to erase unwanted cloned values for clones. Assuming that
no error occurs (the most likely being that an attempt to create an
already existing record occurred) then the record will be ready for
the setting of field values prior to the call to "op_apply".
(op_apply)
post_init Create Create This function is available to provide values for fields that depend
upon other field values (unlike "to_store" this function will later
be called again in case "to_store" causes these values to change).
to_store Create Create This function is available to provide values for fields that depend
upon other field values (that were "set" between the commencment of
the "op_create" and the call to "op_apply"). This is the main place
to put things like "calculated" field values or to set/clear values
due to other values. After the function returns it is expected that
the record should be valid for storing.
post_init Create Create This function is available to provide values for fields that depend
upon other field values (second call for "to_store" side-effects).
validate Create Create Prior to any attempt to store the record in the DB this function is
called to perform all record validation and to provide feedback for
end users of any validation issues.
for_store Create Update If the "validate" call found no issues then this function is called
[starts a tx if not already in one] and then "validate" again prior to record storage. This function is
[secondary *validate* before store] mostly intended for making necessary changes to other records (when
such other records do not require this record to have actually been
created in the DB), and to provide calculated values that rely upon
other DB records. Provided no exception occurs in this function the
record will be stored in the DB with the lock being tranformed into
an "update" lock (necessary for the next function).
after_store Update <none> Assuming no error has occurred previously this function is the last
[commits the tx if one was started] step in the create process which allows further operations that are
expecting the record to exist in the DB to be performed. Often such
operations will be the creating or updating of some related "child"
records, but also could include things like dealing with "external"
files.
-------------------------------------------------------------------------------------------------------------
Passing " " as the key (to automatically create a key) should never be performed in rules code as a generated
key will contain the current time stamp (for the protocol command " " is replaced prior to being logged). For
record creation in rules keys should constructed from a known key with a suffix (e.g. <key>_X or <key>_000001
where <key> already exists and with the latter pattern applicable when needing to create multiple records).
2) Updating an existing record:
Protocol: perform_update <uid> <dtm> <module> <mclass> <key> [=<ver_info>] field1=value1,field2=value2...
Equivalent C++ Code for Rules:
object.op_update( <key> );
object.<field1>( <value1> );
object.<field2>( <value2> );
...
object.op_apply( );
Function Lock Before Lock After Description
-------------------------------------------------------------------------------------------------------------
(op_update - <key>)
post_init Update Update This function is available to provide values for fields that depend
upon other field values.
after_fetch Update Update The lock is acquired before the record is fetched. If both the lock
is acquired and the record is found then this function is generally
used in order to determine the value of transient fields which need
to use other field (or other record field) values.
(op_apply)
post_init Update Update This function is available to provide values for fields that depend
upon other field values (unlike "to_store" this function will later
be called again in case "to_store" causes these values to change).
to_store Update Update This function is available to provide values for fields that depend
upon other field values (that were "set" between the commencment of
the "op_update" and the call to "op_apply"). This is the main place
to put things like "calculated" field values or to set/clear values
due to other values. After the function returns it is expected that
the record should be valid for storing.
post_init Update Update This function is available to provide values for fields that depend
upon other field values (second call for "to_store" side-effects).
validate Update Update Prior to any attempt to store the record in the DB this function is
called to perform all record validation and to provide feedback for
end users of any validation issues.
for_store Update Update If the "validate" call found no issues then this function is called
[starts a tx if not already in one] and then "validate" again prior to record storage. This function is
[secondary *validate* before store] mostly intended for making necessary changes to other records (when
such other records do not require this record to have actually been
created in the DB) and to provid calculated values that depend upon
other DB records.
after_store Update <none> Assuming no error has occurred previously this function is the last
[commits the tx if one was started] step in the update process which allows further operations that are
expecting the record to exist in the DB to be performed. Often such
operations will be the creating or updating of some related "child"
records, but also could include things like dealing with "external"
files.
-------------------------------------------------------------------------------------------------------------
3) Deleting an existing record:
Protocol: perform_destroy <uid> <dtm> <module> <mclass> <key> [=<ver_info>]
Equivalent C++ Code for Rules:
object.op_destroy( <key> );
object.op_apply( );
Function Lock Before Lock After Description
-------------------------------------------------------------------------------------------------------------
(op_destroy - <key>)
post_init Destroy Destroy This function is available to provide values for fields that depend
upon other field values.
after_fetch Destroy Destroy The lock is acquired before the record is fetched and if the record
has any related child records then either cascade locks to all such
records will also have been acquired or an error will have occurred
either due to a cascade restriction or record locking. It should be
noted that the existence of the record will be checked prior to any
cascade checks. If no error has occurred this function is generally
used in order to determine the value of transient fields which need
to use other field (or other record field) values.
can_destroy Destroy Destroy This function is available to provide a means of protecting certain
specific records from being deleted (if they are not protected from
deletion by their state). If a specific error message is wanted for
display then an exception should be thrown in this function.
(op_apply)
for_destroy Destroy Destroy This function is intended for making necessary changes (normally as
[starts a tx if not already in one] updates) to other records that are not simple cascades (such as the
increment or decrement of parent totals). At the point of this call
the record still exists in the DB.
after_destroy Destroy <none> Assuming no error has occurred previously this function is the last
[commits the tx if one was started] to step in the delete process which permits further operations that
expect the record to have been deleted in the DB to occur. Normally
this function is used to clean up "external" files or for some type
of special conditional cascading.
-------------------------------------------------------------------------------------------------------------
4) Fetching an existing record:
Protocol: perform_fetch <module> <mclass> <key> #1 field1,field2...
Equivalent C++ Code for Rules:
object.perform_fetch( <key> ); // NOTE: Via rules a single record fetch will always retrieve all fields.
Function Lock Before Lock After Description
-------------------------------------------------------------------------------------------------------------
(perform_fetch - <key>)
post_init <none> <none> This function is available to provide values for fields that depend
upon other field values.
after_fetch <none> <none> It should be noted that fetching a record using this method doesn't
involve locks at all (for maximum performance). Generally this hook
is used to determine the value of transient fields that depend upon
other field (or another record's field) values.
-------------------------------------------------------------------------------------------------------------
Equivalent C++ Code for Rules:
object.begin_review( <key> ); // NOTE: Via rules a single record fetch will always retrieve all fields.
...
object.finish_review( );
Function Lock Before Lock After Description
-------------------------------------------------------------------------------------------------------------
(begin_review - <key>)
post_init Review Review This function is available to provide values for fields that depend
upon other field values.
after_fetch Review Review This method of fetching a record is available via protocol but only
using the "object" protocol commands (which are only intended to be
used for regression test purposes) therefore it is intended to only
really be used via rules code to ensure that a record will not have
any changes made to it whilst the lock is held. The hook is used as
already mentioned.
(finish_review)
n/a Review <none> This will release the lock (with no other side-effects).
-------------------------------------------------------------------------------------------------------------
5) Fetching multiple existing records:
Protocol: perform_fetch <module> <mclass> "" [#<limit>] field1,field2...
Equivalent C++ Code for Rules:
if( object.iterate_forwards( "", "field1,field2..." ) )
{
do
{
...
} while( object.iterate_next( ) );
}
Function Lock Before Lock After Description
-------------------------------------------------------------------------------------------------------------
(perform_fetch)
post_init <none> <none> This function is available to provide values for fields that depend
upon other field values.
after_fetch <none> <none> Locking is not involved (for maximum performance) and the SQL query
will be limited according to the field list (optional for C++ code)
and fields that are required to determine state and for inter-field
dependencies. The hook is used as already mentioned.
-------------------------------------------------------------------------------------------------------------
It should be noted that when fetching multiple records via the protocol if the record "limit" is omitted then
if is generating PDF a default limit will be used otherwise the number of records returned is unlimited. When
wanting to discontinue iteration in rules code by breaking out of an iteration loop the method "iterate_stop"
needs to be called otherwise object state errors can occur.