Complex CiviCRM Relationship to Role Synchronisation recipe

We recently had a situation where we wanted to synchronise CiviCRM relationships to drupal roles using Drupal rules. We had been doing this for a while - creating a Volunteer role when the contact got a new Volunteer relationship and removing it when the relationship was deleted or expired. However, the problem was that the contact might have another relationship that entitled them to have the Drupal role.

There are many ways to skin this cat. However, in this case the customer has some very clever super-users on board so we wanted to look at a code-free solutions so we wanted to build on the civicrm_entity + rules combo

The 2 key things we needed to add to do this were

rules_list_conditions module

And update civicrm_entity to fetch CiviCRM entities by property

Once we had this we had to build up the rule in components.

1) A component to check if the current relationship has the correct criteria for our role. Here our relationship is type = Trainer OR type = Trainee and descripion = advanced. We choose to create a component and choose 'condition set OR'. We are going to pass this condition set a list of CiviCRM relationships and it will respond with a YES or NO as to whether there is an appropriate trainer relationship in the list.

NOTE I found that is was more reliable using isvolunteer as the variable name than is_volunteer which seem to sometimes get misconstructed as is-volunteer. I didn't get to the bottom of this but recommend you run your words together in your variable names to make life easier


We add our conditions in this case the conditions are

- is_active = 1 AND    relationship_type_id is one of 46, 47, 49, 58, 59, 60

Active Trainer Conditions

Next we need two more rule components to determine the status of our contact. One component will receive a list of relationship types and return TRUE if one of them meets the criteria in our component above. The other receives a contact object & loads the associated relationships passing them into the rule that checks the list of relationship types. We need to create multiple components because we can't load related entities in the conditions section so we have to create the conditions we want as rule components. The rules_conditional module may help a bit with that - but I didn't figure that part out. So here are parts 2 & 3

2) Set up a RULE component - Check Relationship List for Trainer - set this up to receive a relationship LIST & return a truth value for 'istrainer'.  Setting this up as a Parameter + Provided seems to help ensure it is set & we can deal with it being either 0 or 1 in the calling function

Here we use the 'Add ANY' to add a function that will cycle through our relationship list & continue to the Action (set the value istrainer to TRUE) if ANY of the relationships meet the condition. We add our previous component as our condition by choosing 'Add Condition' to the right of our 'ANY' loop. Note that the links below action (add conditional, add switch, add while) were added by the rules_conditional module which I have not yet experimented with.

3) We are now ready to set up an action component (or rule component I expect) that receives a contact as a parameter and provides 'istrainer' as an output. The key here is that we are adding the action 'Fetch CiviCRM Entity By Property' to load a list of the CiviCRM contact's relationships

This returns a relationshiplist which we pass to our previous rule 'Check Relationship for Trainer'  - this will return the variable which we have called 'isatrainer' in this action set and then we set our variable 'istrainer' to equal that (not sure if there is a way to set istrainer directly). Now we have a rule that will take a CiviCRM contact as a paramer and return YES or NO as to whether that contact has a trainer relationship


Phew getting there!! Now we just need to do something based on that - yes another components - 2 actually - 1 will add the trainer role if the contact has the trainer relationship. The other will remove it if not - we'll just look at the add. It receives civicrmcontact & istrainer as variables. Note that in order to have a Drupal user to work on we need to 'Create or Load linked Drupal User Account'


We do the remove much the same and FINALLY we can create our complete rule - this one we create as add rule rather than add component - it looks like this & says

"When a CiviCRM relationship is created or Updated Check if they have a relationship that makes them eligible to be a trainer. If yes, then add the role, if no then remove the role (if it exists)