Rules

Content Rules provide a way for you to wire in business logic behind the content graph. Once they're set up, rules run automatically as content is created, updated and deleted within your branch.

Rules are content nodes with a JSON payload the describes the Conditions and Actions to be triggered.

As with all behaviors, Rule nodes must implement the f:behavior feature. They must be bound to a node upon which to act (either a definition node or a content instance) using a a:has_behavior association.

A Rule consists of the following:

- a set of Conditions
- a set of Actions
- a set of Policy Bindings that determine when the Rule should trigger.

Ultimately, rules are intended to perform one or more Actions against a node.

Suppose for example that you wanted to create a Folder where any content that is dropped into that folder will automatically have it's payload converted to PDF. You might do the following:

  1. Create a rule and call it "Convert to PDF"
  2. Add a "Transform Attachment" Action to the rule and configure it to operate against the "default" attachment.
  3. Bind the Rule to the p:afterCreateAssociatedNode policy of the folder.

Now whenever a file is dropped into the folder, the p:afterCreateAssociatedNode policy triggers and the Rule executes. The Rule evaluates any Conditions that it may have bound to it. If those Conditions are satisfied (or if there are none), then any connected Actions are triggered.

In this case, the Rule gets a hold of the newly dropped file and runs the action against it.

Note that in this example we did not use any Conditions. Conditions are optional.

Policy Bindings

Cloud CMS provides a good number of policy bindings which are raised as content is worked with. These policies provide places where you can hook up your custom logic. When you work on content in Cloud CMS, these policies are triggered all the time. Usually, they're silent since nothing is hooked up. However, once you hook up Rules, your Rule logic (conditions and actions) will begin to do stuff automagically as your editorial team goes about it's daily tasks.

The following policies are available:

{{#article "policies/association"}}Association Policies{{/article}}

  • function beforeAssociate(association)
  • function afterAssociate(association)
  • function beforeUnassociate(association)
  • function afterUnassociate(association)

{{#article "policies/attachment"}}Attachment Policies{{/article}}

  • function beforeReadAttachment(node, attachmentId)
  • function afterReadAttachment(node, attachmentId)
  • function beforeCreateUpdateAttachment(node, attachmentId, contentType, filename)
  • function afterCreateUpdateAttachment(node, Attachment attachment)
  • function beforeDeleteAttachment(node, Attachment attachment)
  • function afterDeleteAttachment(node, Attachment attachment)

{{#article "policies/datalist"}}Data List Policies{{/article}}

  • function beforeAddListItem(item, list)
  • function afterAddListItem(item, list)
  • function beforeUpdateListItem(item, list)
  • function afterUpdateListItem(item, list)
  • function beforeRemoveListItem(item, list)
  • function afterRemoveListItem(item, list)

{{#article "policies/node"}}Node Policies{{/article}}

  • function afterReadNode(node)
  • function beforeCreateNode(node)
  • function afterCreateNode(node)
  • function beforeUpdateNode(node, originalNode)
  • function afterUpdateNode(node, originalNode)
  • function beforeDeleteNode(node, originalNode)
  • function afterDeleteNode(node)
  • function beforeTouchNode(node)
  • function afterTouchNode(node)
  • function beforeAssociateNode(node, association, associatedNode)
  • function afterAssociateNode(node, association, associatedNode)
  • function beforeUpdateAssociatedNode(node, association, associatedNode)
  • function afterUpdateAssociatedNode(node, association, associatedNode)
  • function beforeUnassociateNode(node, association, associatedNode)
  • function afterUnassociateNode(node, association, associatedNode)
  • function beforeAddFeature(node, FeatureDefinition definition, Object configuration)
  • function afterAddFeature(node, FeatureDefinition definition, Object configuration)
  • function beforeUpdateFeature(node, FeatureDefinition definition, Object configuration)
  • function afterUpdateFeature(node, FeatureDefinition definition, Object configuration)
  • function beforeRemoveFeature(node, FeatureDefinition definition, Object configuration)
  • function afterRemoveFeature(node, FeatureDefinition definition, Object configuration);

{{#article "policies/property"}}Property Policies{{/article}}

  • function beforeCreateProperty(node, name, value)
  • function afterCreateProperty(node, name, value)
  • function beforeUpdateProperty(node, name, value, originalNode, originalValue)
  • function afterUpdateProperty(node, name, value, originalNode, originalValue)
  • function beforeDeleteProperty(node, name, value)
  • function afterDeleteProperty(node, name, value)
  • function beforeTouchProperty(node, name, value, originalValue)
  • function afterTouchProperty(node, name, value, originalValue)

Read more about Content Policies within Cloud CMS.

Conditions

Conditions describe things that must be true in order for the Rule to fire off any Actions. Conditions usually consist of tests to check for things like property value matches, content types matches and so forth.

If you put multiple Conditions onto a Rule, all of them must be true in order for the Rule to execute its Actions.

Your Conditions may also contain nested Conditions and utilize boolean operators like and and or.

Actions

Actions are operations that are taken against your content on behalf of the Rule. These can be things like updating content items, setting properties, saving changes, moving content between folders, sending emails or firing off Web Hooks.

Cloud CMS provides a large library of Actions that you can use throughout the product in many places, including Rules. These same actions can also be triggered from Workflows, custom server-side JavaScript and a few other places.

Scripts

Rules aren't the only kinds of behaviors you can use. Cloud CMS lets you write custom server-side JavaScript and bind it to policies. Server-side JavaScript gives you a lot of flexibility as it lets you express conditions and more complex logic using code.

For example, suppose you set up a rule to execute a script for the p:beforeCreateNode policy. You could write a script that looked like this:

function beforeCreateNode(node)
{
    node.properties.category = "shirt";
}

This method signature conforms to the p:beforeCreateNode policy.
For more information, see Node Policies.

Root Scope Variables

The following root-scoped variables will additionally be available when executing a script from within a rule:

  • isMerging will be true if the current rule is executing as part of a merge (from one branch to another).
  • isReleasing will be true if the current rule is executing as part of a release. Note that in this case, isMerging will also be set to true since release execution performs a merge.
  • merge will be set to an object that provides additional information about the ongoing merge (if applicable).

The merge value, if available, will look something like this:

{
    "sourceBranch": scriptSourceBranch,
    "targetBranch": scriptTargetBranch,
    "release": scriptRelease

You can use the merge variable in cases where you need to access information about the source branch, target branch or the release. For example, you might execute the following script to handle the p:beforeCreateNode event:

function beforeCreateNode(node)
{
    if (isMerging && isReleasing)
    {
        if (merge.sourceBranch.properties.family === "dev")
        {
            node.properties.mergeFamily = "dev";
        }
    }    
}

This rather contrived example sets up a situation where a node being created on a target branch (as the result of a merge during a release) will set the mergeFamily variable to dev if it's being merged from a dev branch.

Note also that the p:beforeMergeNode and p:afterMergeNode policies pass the merge context through as a final argument (referred to as mergeContext):

function beforeMergeNode(targetNode, sourceNode, mergeContext);
function afterMergeNode(targetNode, sourceNode, mergeContext);