Using CTools Access Rulesets in module development.

Error message

The spam filter installed on this site is currently unavailable. Per site policy, we are unable to accept new submissions until that problem is resolved. Please try resubmitting the form in a couple of minutes.

CTools is a powerful toolbox for Drupal developers, but there are many features of this huge module that aren't well known or used. I would like to share some of my experience with using one of those lesser-known features: CTools Access Rulesets.

In this article you'll learn how to utilize the nice CTools Access Rulesets GUI in combination with some custom code to limit file downloads based on certain criteria. This promotes generic code and separates the access logic out to a place where it is customizable by a site administrator.

This gives you the ability to use flexible and powerful Panels selection rules outside of Panels.

Introduction

CTools Access Rulesets allow you to create access rules based on different contexts. It is widely used in page manager when we define rules for access to the page. When we enable the ctools_access_ruleset module, we use a UI to create our own access rules (admin/structure/ctools-rulesets/list).

One way we recently used this functionality was to limit private file downloads. I wanted to have a flexible rule that was customizible via UI, one that I would be able to extend if client's requirements changed (and I knew they would). To manage this, we wrote our own module and used hook_file_download to trigger our ctools access ruleset to determine whether we should allow the user to download the file or not.

We decided to base access control on taxonomy terms linked to the node that have the file attached. To do this we can create a ruleset that will have the context as nodes and there we check for the condition of whether or not the specified taxonomy terms are attached to these nodes.

Setting up the rule (in the GUI)

The screenshots below (click to enlarge) will allow us to see the UI interface to see the how to set it up.

First we need to open the list of access rulesets: admin/structure/ctools-rulesets/list

Each rule consists of three parts: basic infomation, contexts, and rules. Basic information is the name and description. I will skip this part.

For the Contexts we add the required context Node.

We also add the Relation to the taxonomy term we want to use. In my case, the term is from the Category vocabulary.


Now lets look at the settings of the Rules.


We have only one Rule based on a taxonomy term. The settings are as follows:


Creating the code

Now let's see how we can execute the ctools ruleset in our own module.

I would like to thank Earl Miles (merlinofchaos) and Kris Vanderwater (EclipseGc) for their support on IRC on this issue.

The key function is ctools_access($access, $context). $context is the array of contexts that we pass to the ruleset. $access is the configuration array. The machine name of my ruleset is document_download_rule.

<?php
 
// Prepare arguments for ctools_access().
  // Name of created ruleset is document_download_rule.
 
$access = array('plugins' => array(
    
0 => array(
      
'name' => 'ruleset:document_download_rule',
      
'settings' => NULL,
      
'context' => array('node_context'),
      
'not' => FALSE,
     ),
   ),
  
'logic' => 'and',
  
'type' => 'none',
  
'settings' => NULL,
  );

 
ctools_include('context');
 
$node_context = ctools_context_create('entity:node', $node);
 
$contexts = array('node_context' => $node_context);

  if (
ctools_access($access, $contexts)) {
   
// Allow access.
 
}
  else {
   
// Deny access.
 
}
?>

$node is the fully loaded node object that we find based on the file $uri. I will skip this part as it is not too important here. However you can take a look at a full example that is attached to this post here: Download Example

If we will decide to extend the ruleset in the future, the only things we will need to do is add new rules and contexts via the UI.

In order to understand how to prepare the $access configuration array, I would recommend doing what I did: enable module page manager, play with access rules by creating rulesets, and debug the $access variable in ctools_access function.

Conclusion

By using CTools Access Rulesets we created a custom module, which allowed us to limit file downloads based on certain criteria. We showed that this method is a way to quickly write really flexible code that can adapt to changing needs.

It should give you a great perspective on what is possible using CTools Access Rulesets and stir your imagination. Have you used CTools Access Rulesets in a clever way in the past? Please share your experiences in the comments.

Thanks for reading!