web-dev-qa-db-fra.com

Avez-vous un exemple de rappel d'accès hook_menu ()?

J'ai téléchargé le projet examples , mais dans le module menu_example tous les access callback sont définis sur true .. difficile de comprendre comment cela fonctionne.

Dans mon exemple, mon entrée de menu doit être visible sur les nœuds, mais uniquement pour les rôles qui ont les autorisations de modifier ses propres nœuds.

Je ne peux pas trouver un exemple un peu plus détaillé d'un rappel d'accès.

Quelqu'un en a-t-il un?

18
Strae

Modifier: j'ai raté la partie concernant l'autorisation "Modifier son propre nœud", car vous devez non seulement vérifier l'autorisation, mais également si ce nœud appartient à l'utilisateur actuel. J'ai mis à jour mon exemple ci-dessous mais je laisse l'explication ci-dessus telle qu'elle était.

Votre entrée de menu est-elle sous nœud/nid (par exemple, nœud/1234/quelque chose)? Ensuite, vous n'avez probablement même pas besoin d'un rappel d'accès personnalisé.

Si vous définissez votre chemin de menu comme dans l'exemple suivant, il appellera uniquement le rappel d'accès (et donc le rappel de votre page), si vous visualisez un nœud valide.

'node/%node/something'

Cela signifie qu'il appellera node_load (1234) pour l'exemple ci-dessus et ne continuera que si un objet node valide est retourné. Vous pouvez donc définir votre autorisation avec des arguments d'accès comme d'habitude.

Cela dit, écrire un rappel d'accès est vraiment simple. C'est juste une fonction qui recevra les arguments que vous avez définis dans les arguments d'accès. Par exemple, le rappel d'accès par défaut est ser_access () et lorsque vous définissez vos arguments d'accès comme 'access arguments' => array('a permission string'), il en résulte l'appel suivant: user_access('a permission string').

Si vous avez plusieurs arguments, ceux-ci seront passés comme deuxième, troisième et ainsi de suite argument à votre fonction. Pour accéder au nœud actuellement actif, vous pouvez utiliser menu_get_object () .

Vous pouvez donc écrire votre rappel d'accès comme ceci, mais encore une fois, vous n'aurez peut-être même pas besoin d'en créer un.

function yourmodule_access_check() {
  global $user;
  $node = menu_get_object();

  return $node && $node->uid == $user->uid && user_access('edit own ' . $node->type . ' content');
}

Au lieu de coder en dur la chaîne d'autorisation, vous pouvez la passer comme argument à la fonction ou à tout ce que vous voulez faire.

12
Berdir

Drupal est lui-même un exemple de la façon d'écrire du code.

L'exemple le plus simple est gregator_menu () , qui contient le code suivant.

  $items['admin/config/services/aggregator'] = array(
    'title' => 'Feed aggregator', 
    'description' => "Configure which content your site aggregates from other sites, how often it polls them, and how they're categorized.", 
    'page callback' => 'aggregator_admin_overview', 
    'access arguments' => array('administer news feeds'), 
    'weight' => 10, 
    'file' => 'aggregator.admin.inc',
  );
  $items['admin/config/services/aggregator/add/feed'] = array(
    'title' => 'Add feed', 
    'page callback' => 'drupal_get_form', 
    'page arguments' => array('aggregator_form_feed'), 
    'access arguments' => array('administer news feeds'), 
    'type' => MENU_LOCAL_ACTION, 
    'file' => 'aggregator.admin.inc',
  );

Dans ce cas, le rappel d'accès est la valeur par défaut ( ser_access () ) et les arguments d'accès sont un tableau contenant la chaîne de l'autorisation. Le code ne peut pas vérifier plus qu'une autorisation; si les autorisations à vérifier sont deux ou si les conditions à vérifier ne sont pas uniquement des autorisations, le rappel d'accès doit être différent, y compris personnalisé.

node_menu () définir certains menus qui utilisent un rappel d'accès différent de celui par défaut. La fonction contient le code suivant.

  foreach (node_type_get_types() as $type) {
    $type_url_str = str_replace('_', '-', $type->type);
    $items['node/add/' . $type_url_str] = array(
      'title' => $type->name, 
      'title callback' => 'check_plain', 
      'page callback' => 'node_add', 
      'page arguments' => array($type->type), 
      'access callback' => 'node_access', 
      'access arguments' => array('create', $type->type), 
      'description' => $type->description, 
      'file' => 'node.pages.inc',
    );
  }

La fonction définie comme rappel d'accès ( node_access () ) est la suivante:

function node_access($op, $node, $account = NULL) {
  $rights = &drupal_static(__FUNCTION__, array());

  if (!$node || !in_array($op, array('view', 'update', 'delete', 'create'), TRUE)) {
    // If there was no node to check against, or the $op was not one of the
    // supported ones, we return access denied.
    return FALSE;
  }
  // If no user object is supplied, the access check is for the current user.
  if (empty($account)) {
    $account = $GLOBALS['user'];
  }

  // $node may be either an object or a node type. Since node types cannot be
  // an integer, use either nid or type as the static cache id.

  $cid = is_object($node) ? $node->nid : $node;

  // If we've already checked access for this node, user and op, return from
  // cache.
  if (isset($rights[$account->uid][$cid][$op])) {
    return $rights[$account->uid][$cid][$op];
  }

  if (user_access('bypass node access', $account)) {
    $rights[$account->uid][$cid][$op] = TRUE;
    return TRUE;
  }
  if (!user_access('access content', $account)) {
    $rights[$account->uid][$cid][$op] = FALSE;
    return FALSE;
  }

  // We grant access to the node if both of the following conditions are met:
  // - No modules say to deny access.
  // - At least one module says to grant access.
  // If no module specified either allow or deny, we fall back to the
  // node_access table.
  $access = module_invoke_all('node_access', $node, $op, $account);
  if (in_array(NODE_ACCESS_DENY, $access, TRUE)) {
    $rights[$account->uid][$cid][$op] = FALSE;
    return FALSE;
  }
  elseif (in_array(NODE_ACCESS_ALLOW, $access, TRUE)) {
    $rights[$account->uid][$cid][$op] = TRUE;
    return TRUE;
  }

  // Check if authors can view their own unpublished nodes.
  if ($op == 'view' && !$node->status && user_access('view own unpublished content', $account) && $account->uid == $node->uid && $account->uid != 0) {
    $rights[$account->uid][$cid][$op] = TRUE;
    return TRUE;
  }

  // If the module did not override the access rights, use those set in the
  // node_access table.
  if ($op != 'create' && $node->nid) {
    if (module_implements('node_grants')) {
      $query = db_select('node_access');
      $query->addExpression('1');
      $query->condition('grant_' . $op, 1, '>=');
      $nids = db_or()->condition('nid', $node->nid);
      if ($node->status) {
        $nids->condition('nid', 0);
      }
      $query->condition($nids);
      $query->range(0, 1);

      $grants = db_or();
      foreach (node_access_grants($op, $account) as $realm => $gids) {
        foreach ($gids as $gid) {
          $grants->condition(db_and()
            ->condition('gid', $gid)
            ->condition('realm', $realm)
          );
        }
      }
      if (count($grants) > 0) {
        $query->condition($grants);
      }
      $result =  (bool) $query
        ->execute()
        ->fetchField();
      $rights[$account->uid][$cid][$op] = $result;
      return $result;
    }
    elseif (is_object($node) && $op == 'view' && $node->status) {
      // If no modules implement hook_node_grants(), the default behavior is to
      // allow all users to view published nodes, so reflect that here.
      $rights[$account->uid][$cid][$op] = TRUE;
      return TRUE;
    }
  }

  return FALSE;
}

Il y a trois points à noter:

  • Les arguments déclarés avec "arguments d'accès" seront passés à la fonction dans le même ordre; la fonction utilise un troisième paramètre car elle n'est pas utilisée uniquement pour le rappel d'accès.
  • La fonction renvoie TRUE si l'utilisateur a accès au menu et FALSE si l'utilisateur n'a pas accès au menu.
  • Un rappel d'accès peut également être utilisé lorsqu'un menu doit être affiché uniquement dans des circonstances spécifiques.
19
kiamlaluno