Publishing rules

A rule can be thought of as a type that has been extended to become embeddable. Here are some similarities and differences:

Similarities

Differences

CFProperty is used to define a rule property.

Content type properties are usually for display, rule properties are used to specify behaviour

Rules and their properties are deployed through the admin

Rules are deployed through the Rules interface

You get and set properties with the getData and setData methods

Rules are stored in the rules subdirectory of packages


A rule extends farcry.farcry_core.packages.rules.rules

 

A rule implements update and execute methods, not edit and display.

 

As far as I'm aware, there are no custom cfcomponent attributes for a rule.

This document will be mostly concerned with the method implementations, as most of the other parts are covered elsewhere (eg in Custom Types).

Update

This method creates and handles the form used to edit a rule. When you click on a container and add this rule, you will be shown this form. This is a "view" method, in the sense that the output of this method is put directly into the window. You don't need to worry about which container the rule is in or the order of the rules, just with the form that a user will use to customize the rule.

The text rule may be the simplest rule possible: it outputs a title and a chunk of text. Here is its update method (3.01):

Update Method (ruleText.cfc)
<cffunction name="update" output="true">
        <cfargument name="objectID" required="Yes" type="uuid" default="">
        <cfargument name="label" required="no" type="string" default="">

        <cfimport taglib="/farcry/farcry_core/tags/navajo/" prefix="nj">
        <cfimport taglib="/farcry/farcry_core/tags/widgets" prefix="widgets">

        <cfparam name="form.title" default="">
        <cfparam name="form.text" default="">

        <cfset stObj = this.getData(arguments.objectid)>

        <!--- save submitted data --->
        <cfif isDefined("form.submit")>
                <cfscript>
                        stObj.title = form.title;
                        stObj.text = form.text;
                </cfscript>
                <q4:contentobjectdata typename="#application.rules.ruleText.rulePath#" stProperties="#stObj#" objectID="#stObj.objectID#">
                <!--- Now assign the metadata --->
                <cfset message = "#application.adminBundle[session.dmProfile.locale].updateSuccessful#">
        </cfif>

        <cfif isDefined("message")>
                <div align="center"><strong>#message#</strong></div>
        </cfif>

        <!--- form --->
        <form action="" method="POST">
                <table width="100%" align="center" border="0">
                        <input type="hidden" name="ruleID" value="#stObj.objectID#">
                        <tr>
                                <td align="right"><b>Title</b></td>
                                <td> <input type="text" name="title" value="#stObj.title#"></td>
                        </tr>
                </table>
                <textarea name="text" cols="50" rows="15">#stObj.text#</textarea>
                <div align="center">
                  <input class="normalbttnstyle" type="submit" value="#application.adminBundle[session.dmProfile.locale].go#" name="submit">
            </div>
        </form>
</cffunction>

As you can see, it takes the object id of the rule and a label as arguments. The rest is a very straight forward self-handling form: import tags, get current properties of rule, update the properties if the form was submitted, output the form. The form and the update logic can be as sophisticated as you like. For example, the handpicked rule has a multistage update process using the PLP tags.

Note: I believe that this form does need to be self-handling: if you specify an action it can interfere with the container editing logic.

Execute

This method is called as part of displaying a page, and a container. Execute is slightly more complicated than update: instead of displaying output directly, you need to add content to the request.aInvocations array. You can add two types of data to this array:

  • a struct containing the objectid, typename, and displaymethod of a content type, or
  • a string

Content types have the result of the specified display method outputed to the page, and strings are outputed as is. Which means that the text rule execute method is extremely simple:

Execute Method (ruleText.cfc)
<cffunction name="execute" hint="displays the text Rule on the page" output="false" returntype="void">
        <cfargument name="objectID" required="Yes" type="uuid" default="">
        <cfargument name="dsn" required="false" type="string" default="#application.dsn#">

        <cfset var stObj = getData(arguments.objectid)>
        <cfset var blurb = "">

        <cfif trim(len(stObj.title))>
                <cfset blurb = "<h2>#stObj.title#</h2>">
        </cfif>
        <cfset blurb = "#blurb##stObj.text#">

        <cfif len(trim(blurb))>
                <cfset tmp = arrayAppend(request.aInvocations,blurb)>
        </cfif>
</cffunction>

Or in plain speak: get the rule properties (title and text), construct the output, add the output to the output queue.
Again, object id is a required argument.