Drupal 7 hook_node_access有条件地阻止节点访问

时间:2011-07-29 16:04:43

标签: drupal drupal-7 drupal-hooks

对于所有用户,我需要有条件地阻止访问“消息”类型的节点。用户应该能够查看这些消息节点的唯一方法是成功提交表单。

我是这样开始的:

  function mymodule_node_access($node, $op, $account) {
    if ($op == 'view' && $node->type == 'message') {
      return NODE_ACCESS_DENY;
    }
  }

但是,我希望在成功提交表单后允许对此类型的各个节点进行查看访问:

function form_submit($form, &$form_state) {
  // some logic here  
  $form_state['redirect'] = 'node/255';
}

因此节点255的类型为“message”,我想“解除”此特定节点和该用户的NODE_ACCESS_DENY(+在大多数情况下,这将是一个匿名用户)

有关实现此目标的不同方法的任何建议吗?

2 个答案:

答案 0 :(得分:4)

您可以这样做的唯一方法是在表单提交处理程序中设置一个值,然后由hook_node_access()检查;您可以使用Drupal变量或保存在数据库表中的值。 您需要存储访问该表单的用户的用户ID,以及已提交此表单的每个节点的节点ID。

假设您使用Drupal变量,您可以使用类似于以下代码的代码:

function mymodule_form_submit($form, &$form_state) {
  global $user;
  $message_nid = 255;
  $values = variable_get('access_nid', array());

  if (isset($values[$user->uid])) {
    if (!isset($values[$user->uid][$message_nid])) {
      $values[$user->uid][$message_nid] = $message_nid;
    }
  }
  else {
    $values[$user->uid] = array($message_nid => $message_nid);
  }

  variable_set('access_nid', $values);
  $form_state['redirect'] = 'node/' . $message_nid;
}

function mymodule_node_access($node, $op, $account) {
  $result = NODE_ACCESS_IGNORE;

  if ($op == 'view' && $node->type == 'message') {
    $values = variable_get('access_nid', array());
    if (!empty($values[$account->uid]) {
      if (isset($values[$account->uid][$node->nid])) {
        unset($values[$account->uid][$node->nid]);
        $result = NODE_ACCESS_ALLOW;
      }
      else {
        $result = NODE_ACCESS_DENY;
      }
    }
    else {
      $result = NODE_ACCESS_DENY;
    }
  }
  variable_set('access_nid', $values);

  return $result;
}

要注意,此代码仅允许用户访问节点一次;如果用户第二次尝试访问同一节点,则用户将收到“拒绝访问”错误。如果不需要,则应按如下方式重写第二个函数:

function mymodule_node_access($node, $op, $account) {
  if ($op == 'view' && $node->type == 'message') {
    $values = variable_get('access_nid', array());
    if (!empty($values[$account->uid]) {
      if (isset($values[$account->uid][$node->nid])) {
        return NODE_ACCESS_ALLOW;
      }

      return NODE_ACCESS_DENY;
      }
    }
    else {
      $result = NODE_ACCESS_DENY;
    }
  }

  return NODE_ACCESS_IGNORE;
}

我使用Drupal变量来编写简单的代码;在这种情况下,如果可以创建该内容类型节点的用户很少,则应该使用Drupal变量;如果有许多用户可以创建这些节点,那么使用数据库表会更好 另外,当使用Drupal变量时,Drupal正在使用数据库表;不同之处在于该数据库表的内容始终在内存中加载。如果您需要存储许多数据,则不应使用Drupal变量。

答案 1 :(得分:2)

使用$ _SESSION的修改后的解决方案,因为我主要与匿名用户合作:

function mymodule_form_submit($form, &$form_state) {
  $message_nid = 255;
  if (!isset($_SESSION['node_access'])) {
    $_SESSION['node_access'] = array();
  }
  if (!isset($_SESSION['node_access']['nid'])) {
    $_SESSION['node_access']['nid'] = $message_nid;
  }
  $form_state['redirect'] = 'node/' . $message_nid;
}

function mymodule_node_access($node, $op, $account) {
  $node_access = NODE_ACCESS_IGNORE;
  if ($op == 'view' && $node->type == 'message') {
    if (isset($_SESSION['node_access'] && !empty($_SESSION['node_access'])) {
      if ($node->nid == $_SESSION['node_access']['nid']) {
        unset($_SESSION['node_access']['nid']);
        $node_access = NODE_ACCESS_ALLOW ;
      } else {
        unset($_SESSION['node_access']['nid']);
        $node_access = NODE_ACCESS_DENY;
      }
    } else {
      $node_access = NODE_ACCESS_DENY;
    }
  }
  return $node_access;
}