Introduction to Rules in D7
on
What can I say? rules are a priceless asset when it comes to customizing the functionality of a Drupal site without having to actually code anything. If you embrace them, you will live happier and stress free. Okay, probably an impossible statement considering our field of work, but I have found that knowing how to take advantage of rules effectively inside and out gives me a huge advantage I didn't feel I had before. I have been able to save time, build complex systems faster, and most of all, assess and reduce many of those annoying small customizations requests that threaten to blow a budget, to simple point and click tasks. That last one is a huge advantage and I'll try and give you some good examples in the series of blog post following this one. In this particular post I will go over some rules basics and will try to explain some key concepts. If you've already used rules I do recommend at least skimming over the section "how to NOT break the rules and still be a badass" below.
What is rules exactly and what can it do?
- Rules is a module
- Rules can be simple or even the most complex events/conditions/actions workflows. It is highly flexible.
- Rules can be triggered in several ways: event triggers, Views Bulk Operations, scheduled rules (on cron), rules ui execute link, and from within custom modules.
- Many contrib modules now include integration with rules by providing events, conditions and/or actions that interact with their module's functionality. This gives you the power to extend that module's functionality in almost any imaginable way.
Where rules comes in handy
How many times has this happened to you? You have finished pretty much everything and the client remembers, "oh yeah we also want ," and you're thinking "yeah..., that does not come out of the box with Drupal and there is nothing that I can think of that easily does that. This may take days." Well it is likely that if that "simple" request involves reacting to an event such as a user logging in, a profile/node/taxonomy/flag or any entity being created, updated, deleted, then you can do it with rules. Or... if that "simple" customization request involves executing an action of any kind like sending mail or acting on any entity in your system then it is likely that rules combined with views and views bulk operations can do it.
If all else fails, and rules can get you part of the way there, ( for example, say there is an event that would work, but there is no action that meets your needs) then if you can at least take advantage of the rules API then you are likely already half way through your customization task at the outset. Which is way better in my opinion then not being anywhere. By leveraging rules' UI and event, condition, action system you can create your own actions, conditions and/or events that get you the rest of the way without having to code it all yourself.
Some rules terms that are good to know
Event - A rules event is what is used to trigger reaction rules. Contrib modules can define events that they then trigger when something happens during the processing of that module's code. An example is the entity integration for rules. Every entity that uses the entity api CRUD integration automatically has several events that will fire when certain CRUD operations are performed on that entity. For example: is viewed, After saving a new , After updating an , Before saving a , and Before deleting a .
Condition - A rules condition is essentially a set of if statements. In order for the rule's action to be executed the combination of conditions need to evaluate to TRUE. Conditions can be nested in AND and OR blocks to build what can be considered more complex if statement. So something like:
Conditions: Conditiion A Condition B OR Conditon C Condition D AND Conditon E Condition F
Could be thought of as the following if statement:
<?php if (Condition A && Condition B &&(Conditon C || Conditon D || (Conditon E && Condition F) ) ) { ... } ?>
Action - Essentially a function call. A rules action does something. Everything from sending email and displaying messages to a user, to assigning roles, manipulating field data on entities like nodes, and busting a cap in some mofo's user account.
Variables in rules:
- Provided - Provided variables are data, be it simple data types such as a booleans, integers or dates, to complex objects like entities. Events usually provide variables. For example the "content is viewed" event provides the full node object for the node that is being viewed. You can then pass that provided variable to a condition or action as an input parameter.
- Parameter - You can think of a parameter as a being the same thing as a function parameter or a variable. Parameters are required variables that you must pass to conditions or actions to be evaluated or operated on.
Reaction rules - A reaction rule is a set of actions that get triggered by a particular event, given that a set of conditions resolve to true.
Rules components - Rules components are basically pieces that can be used to build more complex reaction rules. They come in several flavo(u)rs:
- Rule - a set of conditions and resulting actions that do not have a particular event that triggers them, but which can be used as actions from other rules. They can also be executed by Views Bulk Operations.
- Rule set - a set of rule components that do not have a particular event that triggers them, but which can be used as actions from other rules. They can also be executed by Views Bulk Operation.
- Condition set - a set of conditions that can be used to evaluate whether or not to execute a reaction rule or rule component's actions. They are useful when multiple rules use the same set of conditions. Thus, you build it once and use it in many places.
- Action set - a set of actions that can be executed by including them as a single action from a reaction rule, rule component or within a rule set rule component. They are useful when you have common tasks that need to be executed from several different places.
Scheduled rules - sets of conditions and actions that get executed on a regular basis via cron.
How to NOT break the rules and still be a badass
"Cool guys don't look at explosions. They blow things up and walk away." Badasses are by definition risk takers. They get it done, fast, focused and without looking back. However, to be a badass that survives the fast lane of site development you got to be cold and calculated as well. Using rules to get where you're going fast is wise, but you gotta be mindful of your direction (bundle types) and keep an eye out for pot holes (Null values):
Revealing bundle specific fields
I have come across numerous posts where people are frustrated that they cannot access their fields on their entities through rules. Most often node fields, but the same goes for all entities in general. This is because when a rule accepts a parameter from an event/action/condition it assumes nothing about it other then its base type. So when we're considering entities that's: node, user, taxonomy, flag, relation, etc. However, nothing about the bundle is included.... most of the time. By default you will have access to all the entity's properties since they are a part of an entities base db table and are directly associated with the entity regardless of bundle type. However, fields are associated with specific bundles. Thus, you need to use one of two conditions to expose the fields associated with a bundle:
- 'entity has field' - reveals a specific field. That is provided it is present on the entity parameter input into the condition. If the node does not have the field then the rule will stop execution there. For example you may have a field called 'classified' on the article node type but not on all others. If you have a rule that is triggered on the node created event and you use an 'entity has field' condition and select the 'classified' field, the condition will pass for articles but not others. Immediately after the 'entity has field' condition you will now be able to use that field in other conditions. It will also be made available to the actions that follow.
- 'data comparison' - Use this condition to compare the 'type' property of an entity and it will reveal all the fields associated with the respective bundle. Most of the time, I guess for consistency, developers use 'type' as the property that defines the bundle type. Sometimes not, as is the case with the relation module; it uses 'relation-type'. Regardless if you use this comparison it will give you all the access you need for your entities. Its almost a default in every entity related rule I create. Immediately after you use this rule in the rules conditions weighted stack you will be able to use all the entities field in further conditions and they will be available for use in the actions that follow.
- 'entity is of type' - This particular rule is rarely of use except in the case where you may have a generic entity defined as the provided variable for an event or rule component. In this case you can use this to reveal all of the entity's properties. The you can follow it up with a 'data comparison' condition against its bundle type to reveal all its fields. Easy peasy in theory. I have not actually ever come across this in reality.
Check your data before using it (NULL speed ahead)
The absolute killer of any rule is when you use a condition or action to evaluate/modify a parameter that is NULL. If you try to do a data comparison on a field that has no value your rule will throw an exception and grind to an immediate halt (NULL speed). To avoid this you should use the following rule of thumb:
- Always use a 'Data value is empty' condition and negate it so you end up with a 'NOT data value is empty' condition. Always!
This checks for "empty" values which includes NULL, 0, FALSE, ARRAY{}, "", etc. Literally the empty() PHP function. Add it before adding any other conditions or actions that use this field or its sub-fields as an input parameter. If you fail to do this, you will surely be sorry, which sucks. True badasses don't have to apologize because when things get hairy it was all part of the plan and you don't look back. Right?
In summary: to be a badass, don't break the rules ... module.
Further
I will be posting some actual examples of how to use rules in a series of follow up blogs. So stay tuned.
Potentially some helpful photos:
In the following image I reveal all the commerce product fields for the event product bundle by adding a "Data comparison" condition on its type property.
The next image shows the rules UI for the "Data value is empty" negated condition.