Drupal 7 tutorial: Working with entity reference fields in rules
While there are a couple of modules that can be used to easily set up entity reference field relationships, in particular the corresponding entity references module, it’s also possible to do create these kinds of relationships with rules. While initially more complicated to set up (though not requiring a dedicated module), the result is a more powerful setup that can be easily cloned and extended with additional actions and conditions – for example, sending e-mails, displaying messages on the site, or changing the value of a third field.
Entities and Entity References
Drupal 7 is built around entities and entity bundles. To understand this concept, it’s necessary to look back to how things were in Drupal 6. D6 used a system of nodes, expanded by the CCK module to provide configurable content types. Content types have to be types of node by definition, and come with comments, revisions etc that may not be relevant in many use cases and cause an overhead.
With entities, there is no longer anything special about nodes. In Drupal 7, nodes, comments and users are all examples of entities, configured from the same base entity system. It’s now possible to create new entity types and many Drupal 7 modules take advantage of this to provide enhanced functionality and performance – for example, the Commerce module with its line item entity type and profile2 module’s profile types.
Entity references replace the role of the user and node reference fields from CCK. These field types allow the definition of relationships between two things (e.g. a user and a node). There are two modules commonly used to enable entity references in Drupal 7:
References is a simple module which emulates the node and user reference fields from Drupal 6. It is easy to configure and use.
Entity reference is a powerful module which is not restricted to any predefined entities like the References module. It is possible to create references to any entity type, including custom entities. The module is a little more complicated to set up and use, particularly for anyone previously unfamiliar with reference fields. There is a module to migrate from references to this module should referencing other entity types become a requirement.
Both modules work with rules in the same way, but if you wish to work with more than just user, node and taxonomy term entities you will need entity_reference.
Creating a synced client / manager relationship in rules
In this example, the user entity can have an attached customer profile or a manager profile, containing different fields, using the profile2 module.
The client has a user reference field called “manager”, which can only contain one item, and the manager has a user reference field called “clients” which may contain multiple values.
When a manager is assigned to a client, using the manager field on the client’s profile, the objective is to update the “clients” field on the manager’s profile to match.
We are also going to set up a second rule that fires only when a currently assigned manager is removed or changed, and to make things more fun we have a “past clients” reference field for the managers which former clients should be prepended to.
You will need the Rules and token modules installed and enabled
The basic rule: Add client to the manager’s ‘clients’ entity reference field when a manager is assigned to a client.
Event and conditions
Event: After updating an existing profile
To have access to the relevant fields later on and to be sure the rule only fires if the field is not empty:
- Condition: Entity has field
- Parameter: Entity: [profile2]
- Field: field_current_manager
- Add an action “Fetch entity by ID”
We need to load the entity that will be altered by the other actions. The type of this entity is User – the user who is being assigned as the client’s manager.
- Entity type = User
- Data selector= profile2:user:profile-client:field-current-manager:uid
- Provides variable “manager”
- note that this is actually accessing data through the entity reference field to get the new manager’s UID – pretty cool!
- Add an action “Add an item to a list” – this is needed rather than ‘set value’ as the clients field can hold multiple values. We use the ‘entity fetched’ variable provided by the previous step to achieve this:
- List to be added to: manager:profile-manager:field-clients
- Item to be added: profile2:user (the user of the client profile being updated)
- Check the box “enforce uniqueness” and select “prepend to the list” if you wish to have newest clients at the top.
You could choose to add other actions, such as to display a message on the site such as “Assigned manager is [token value]” or send an e-mail. These may require the addition of a condition that makes the rule only fire if the client did not have a manager before (use a data comparison) – as currently the rule fires every time a profile is updated – but this does not cause any issues if “enforce uniqueness” is checked.
You can also have this rule react to profiles being created if the manager may be delegated when data is first entered into the profile. Otherwise profiles would have to be saved twice in this situation. To do this, add a second event: After saving a new profile. You can also clone this rule and change the event for greater power.
Rule Two: Adding to a manager’s past clients list when a manager is changed or removed
With a second rule we can react in two situations. When a manager is changed or removed from the manager field (the new rule), and when a manager is assigned and the manager field was empty (the first rule – which will need an extra condition)
- Clone the first rule. Call it “Sync fields when manager is changed and update old manager’s past clients field”
- New condition: NOT Data comparison:
This makes sure that the rule only fires if the new manager is different to the old one (to prevent the rule firing when the profile is updated, but this field hasn’t been changed)
- New condition: NOT Data value is empty:
So the rule only fires when there was a previous manager assigned. It would otherwise also fire in the same situations as the first rule.
- New action ”Fetch entity by ID”
Load the old manager’s user entity
- Entity type = User
- Data selector= profile2-unchanged:user:profile-client:field-current-manager:uid
- Provides variable “old-manager”
- New action: Add an item to a list:
- List to be added to: old-manager:profile-manager:field-past-clients
- Item to be added: profile2:user
- New action: Remove item from a list
- List: Selected list: old-manager:profile-manager:field-clients
- Item to remove: profile2:user
Again, there are plenty of avenues for extending this with new actions. For example, “Display a message on the site” – a message helpful for admins might be:
[profile2:user]‘s manager set to [profile2:field-manager] – Old manager was [old-manager:name]
Adjusting the first rule
To prevent the first rule from also firing in situations where the second does, add a new condition to the first rule:
- Condition: Data value is empty
- Data to check: profile2-unchanged:field-current-manager
Two way relationships should be set up using another rule with inverse data selectors and if applicable, a different event to react to. Hopefully this article helps illustrate what can be achieved with rules and entity references.