Warning: You are viewing old, legacy content. Kept for posterity. Information is out of date. Code samples probably don't work. My opinions have probably changed. Browse at your own risk.
Apr 23, 2014
In this new series for my blog, I’ll be documenting some common design patterns for Drupal site builds. This first post is about the State Machine pattern, which is something I’ve used on several sites recently.
First, let me explain what I mean by “pattern”. If you are already familiar with design patterns in Object-oriented software then you can probably skip this bit, but I think it’s useful for context.
Here’s a quote from the original Gang of Four book on design patterns. That book is about design of object-oriented software, but I think it applies to Drupal development too. The quote is from p.1 of the book, apologies if I offend anyone by bastardising it. I’ve taken the liberty of substituting the words “Designing object-oriented software” with “building Drupal sites”, and a few other substitutions to make my point…
[Building large maintainable Drupal sites] is hard… Your design should be specific to the problem at hand but also general enough to address future problems and requirements [and be maintainable]… Experienced [Drupal site builders] will tell you that a reusable and flexible design is difficult if not impossible to get “right” the first time.
Yet experienced [Drupal site builders] do make good designs. Meanwhile new [site builders] are overwhelmed by the options available and tend to fall back on non-[Drupal] techniques they’ve used before. It takes a long time for novices to learn what good [Drupal site building] is all about. Experienced [site builders] evidently know something inexperienced ones don’t. What is it?
One thing expert [site builders] know NOT to do is solve every problem from first principles. Rather, they reuse solutions that have worked for them in the past. When they find a good solution, they use it again and again. Such experience is part of what makes them experts.
So I’ve been looking at what these “good solutions” are that I might have been using, and as I identify them I’ve been documenting them along the same lines of the original design patterns from the Gang of Four book:
So, first let’s look at what a state machine is, and what problems it solves, before going on to look at how to configure it in Drupal.
A state machine is a theoretical computer science concept that provides a mathematical basis for modelling computation. But don’t worry, the kind of state machines we’ll be using don’t require a degree in computer science to understand.
All you really need to know is that the state machine (or more correctly a Finite State Machine) has a finite number of “states” it can be in and the machine is only ever in one of these states at a time, it’s current state. The state machine can change from one state to another triggered by an event or condition. This change of state is called a transition. A state machine is typically visualised using a state machine diagram, for example:
As you can see the states are represented by an ellipse with the name of the state inside, the arrows denote the possible transitions. You can also see how the entry point and exit point would be notated.
Here’s a (very simplified) example of a ticket in an agile issue queue. In reality this would probably have several other states but for the sake of this example, here’s a simple state machine for the ticket:
A state machine is defined by the list of possible states and the event/condition that triggers each transition.
If you’re reading this and thinking “Events”, “Conditions”, sounds a bit like Drupal Rules, then you’ve already worked out how we’re going to implement this in Drupal!
In this simple ticket example the states are “In progress”, “Approval”, and “Finished”. The transitions are “Completed”, “Rejected”, “Accepted”.
###When to use it?
It might be useful to think that in business speak, when they say “business processes” they are actually talking about state machines. Here are some cases when you might want to think about state machines:
Drawing out a state machine diagram to model this kinds of problems can be really useful to help identify any “edge-case” scenarios you may not have thought of, and capture them early in the design process. It also shows you exactly what you need to test further along in the site build.
###Let’s build it
As with anything in Drupal there are several ways to achieve this functionality, in fact there’s even a State Machine module, but that relies on creating custom plugins. If you’re a developer you might want to take a look at this module.
Workbench Moderation and various other workflow modules include a state machine implementation for a specific purpose.
The approach documented here is suitable for site builders, is flexible, and provides a neat solution that can be configured using the following contributed modules:
I said before that the state machine is defined by it’s set of possible states and set of transitions. In Drupal we’ll be using a simple list field to store the list of possible states for the node.
In a recent post on Drupalize.me they mention the addition of the ability to hide form fields in Drupal 8 core. In Drupal 7 we need a module to help us do this. In this case we are adding a field that will never be directly edited by the user so we just deny access to edit that field using the Field Permissions module.
For the simple ticket example, we have 3 states. So use an integer list field with the following allowed values:
I said that the state machine was defined by the set of possible states (implemented by our list field), and a set of transitions. These transitions can be implemented using the Rules Link module.
Using the Rules Link module you can add a button to the ticket node which manipulates the “state” value preventing the user from actually editing the value in the state field directly, and thus enforcing the workflow defined in our state machine.
Each “Rules link” is configured in two parts. First you define the conditions for when the link should be visible using standard Rules conditions. Secondly, you use the rules reaction to set the value of the state field to the new value (and perform any other actions that you want as a side effect of the transition).
It’s good to follow a principle of audit-ability, so you probably need to keep the transition history. A simple solution might be to add a timestamp field such as “confirmed at” to mark when it went to confirmed state. If using node, you could log revisions to track state changes in the revision log for the node. Or you could look at Messages module to log messages when state changes happen.
If you’re interested in learning more from my 7 years of Drupal experience (and if you’re based in London) why not join me for Everything I Know About Drupal an intensive 2-day Drupal training I’ve been working on. It’s taken a lot of preparation, and there’s still a small number of tickets available. You can find more information on my blog post about it or grab a ticket on the Eventbrite page.