advanced drupal views access control

out of the box, the views module allows you to specify access to the view according to user role. this is a critical feature, but sometimes it's not enough. for example, sometimes you may want the view access to depend on the arguments to the view.

specifically, let's suppose that we have implemented facebook-style threaded mail, and we want to use a view to display all the messages in a thread. the thread id is an argument passed to the view. we only wish to allow the view to be accessed by one of the authors of the thread, or users with the 'administer messages' permission.

here's a three step approach to resolving this dilemna :

step one. create a new access hook in the views module

right after

  // Administrator privileges
  if (user_access('access all views', $account)) {
    return TRUE;
  }

add

  // Call a hook that lets a module define access permissions for the view
  $access_func = "views_access_$view->name";
  if(function_exists($access_func))
  {
  return $access_func($view);
  }

step two. implement your new hook

if your view is called message_thread then create a function views_access_message_thread($view) method.

step three. force views to NOT cache the access control settings for this view

okay, this part is a little hokey. the easiest way to do this is to tell the views module that your view has inline arguments. when you are defining the URL for your view in the views setting explicitly include the arguments, even if they occur at the end of the URL.

for example, if your page URL is view/message and then you are passing the thread id as an argument, define the page URL as view/message/$arg.

if you don't perform this step, then the views module will evaluate the access control for view/message/10 for a user, cache that result, and use that result for a subsequent request to view/message/34.

Looking at the posted date,

Looking at the posted date, they were talking about Views 1.x when this was written. Nice comment though David. That's what *I* was looking for. A sample access handler! =)

Hrmm, no need to hack views.

Hrmm, no need to hack views. Just implement a views_plugin_access.

First define hook_views_plugins() in your module. Something like so:

<?php
/**
* Implementation of hook_views_plugin().
*/
function dra_views_plugins() {
  return array(
   
'access' => array(
     
'parent' => array(
       
'no ui' => TRUE,
       
'handler' => 'views_plugin_access',
       
'parent' => '',
      ),
     
'arguments' => array(
       
'title' => t('Arguments'),
       
'help' => t('Access will be granted to users with permissions based on the current arguments.'),
       
'handler' => 'views_plugin_access_arguments',
       
'uses options' => TRUE,
       
'path' => drupal_get_path('module', 'dra') . '/includes/plugins',
      ),
    ),
  );
}
?>

Then, create a file called 'views_plugin_access_arguments.inc and make sure it ends up inside your chosen path (see the function above). Something like so:

<?php
// $Id$

/**
* A plugin to handle access control based on the arguments.
*/
class views_plugin_access_arguments extends views_plugin_access {
 
/**
   * Initialize the plugin.
   *
   * @param $view
   *   The view object.
   * @param $display
   *   The display handler.
   */
 
function init(&$view, &$display) {
   
$this->view = &$view;
   
$this->display = &$display;
   
$this->options = array();

    if (
is_object($display->handler)) {
   
// Note: The below is read only.
     
$this->options = $display->handler->get_option('access');
    }
  }

 
/**
   * Retrieve the default options when this is a new access
   * control plugin
   */
 
function option_defaults(&$options) { }

 
/**
   * Provide the default form for setting options.
   */
 
function options_form(&$form, &$form_state) { }

 
/**
   * Provide the default form form for validating options
   */
 
function options_validate(&$form, &$form_state) { }

 
/**
   * Provide the default form form for submitting options
   */
 
function options_submit(&$form, &$form_state) { }

 
/**
   * Return a string to display as the clickable title for the
   * access control.
   */
 
function summary_title() {
    return
t('Access by arguments');
  }

 
/**
   * Determine if the current user has access or not.
   */
 
function access($account) {
   
// default to no access control.
   
return TRUE;
  }

 
/**
   * Determine the access callback and arguments.
   *
   * This information will be embedded in the menu in order to reduce
   * performance hits during menu item access testing, which happens
   * a lot.
   *
   * @return an array; the first item should be the function to call,
   *   and the second item should be an array of arguments. The first
   *   item may also be TRUE (bool only) which will indicate no
   *   access control.)
   */
 
function get_access_callback() {
   
// default to no access control.
   
return TRUE;
  }
}
?>

Obviously you'll have to adjust the stuff up top a lot because currently this class is a duplicate of the empty class provided in views as a placeholder parent for the other access control classes, but this gets you started.

Nice post. Just what I was

Nice post. Just what I was looking for. I'm surprised that this sort of access control isn't already available for views.

For anyone else looking at this, it might be useful to add:

// Call a hook that lets a module define access permissions for the view
$access_func = "views_access_$view->name";
if (function_exists($access_func))
{
- return $access_func($view);
+ return $access_func($view, $account);
}

In the above changes to the views module.

Is modifying 3rd party module code the only way to gain more modular access control for views?

post new comment

the content of this field is kept private and will not be shown publicly.
  • web page addresses and e-mail addresses turn into links automatically.
  • allowed html tags: <h2> <h3> <h4> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • lines and paragraphs break automatically.
  • you may post code using <code>...</code> (generic) or <?php ... ?> (highlighted php) tags.

more information about formatting options

captcha
are you human? we hope so.
copy the characters (respecting upper/lower case) from the image.